/DrowsyDromedary

REST interface for MongoDB written in Ruby

Primary LanguageRuby

Build Status

DrowsyDromedary

DrowsyDromedary is the Ruby answer to Sleepy.Mongoose, a REST interface for MongoDB.

Quickstart

You'll need a working Ruby environment (tested on 1.9) with Bundler installed.

cd into the directory where you clonedd the DrowsyDromedary source and run:

bundle
bundle exec rackup

Drowsy should now be running at http://localhost:9292, talking to your mongod running on localhost. Currently Drowsy cannot talk to a mongod instance on another machine, but this will likely change in the future.

Production Deployment

DrowsyDromedary should work with any Rack container. We use Phusion Passenger with Apache.

To deploy with Passenger:

  1. Clone Drowsy and create a virtual host for it. Point the DocumentRoot to Drowsy's public subdirectory.
  2. Install Passenger for Apache
  3. cd into the Drowsy install dirctory and run:
gem install bundler
bundle --without development

DrowsyDromedary should now be up and running.

Running RSpec Tests

bundle
bundle exec rspec -c -fd spec.rb

Security

By default DrowsyDromedary is wide open. This means that your entire MongoDB system will be exposed.

If you are publicly exposing your Drowsy, it is extremely important to lock down access to the service. This can be done with additional configuration to the Rack container running your app. For example, if you are deploying using Apache (via Passenger), you could limit access to specific hosts and/or implement HTTP authentication using mod_auth.

Another option is to add Rack middleware for authorization and authentication. This would be done by modifying Drowsy's config.ru file. Warden is a good option.

CORS (Cross-domain Browser Requests)

The default DrowsyDromedary configuration has an open CORS configuration. Cross-domain browser requests to Drowsy are allowed from all domains for all HTTP methods.

CORS access can be restricted by modifying the Rack::Cors section of Drowsy's config.ru file.

Note that due to some questionable decisions in the CORS spec, CORS requests that result in an error (404, 500, etc.) will always have a blank body (i.e. no detailed error message). In some browsers the error status code is also obscured and always reported as 0 instead of the real code. If you want better error handling, consider putting DrowsyDromedary behind a same-origin reverse proxy.

Dates/Times

Date/Times values in the databse (i.e. ISODate objects) are represented in Drowsy's JSON responses as:

{ "$date": "2013-01-24T06:40:43.0Z" }

Likewise, if you want Drowsy to store a date as an ISODate, send your data in the same format. The string value can be anything parsable by Ruby's Time.parse(), but it's probalby best to stick to the ISO8601 format. For example, in JavaScript:

var date = new Date();
dateJSON = { "$date": date.toJSON() };

Usage

Usage examples with browser-side JavaScript frameworks:

API

Replace db with your database name and collection with your collection name. All parameters must be given as valid JSON strings, and all responses (including errors) are returned in JSON format.

GET /

List databases

Response

Status: 200

[
  "groceries",
  "fridge",
  "pantry"
]

POST /

Create a database

Parameters

db

  • The name of the database to create.

GET /db

List collections in a database

Response
[
  "fruits",
  "vegetables",
  "snacks"
]

POST /db

Create a collection in a database

Parameters

collection

  • The name of the collection to create.

GET /db/collection

List items in a collection

Parameters

selector

sort

  • An array of property-order pairs to sort on.
  • Examples:
    • ["fruit","DESC"] (sort by the 'fruit' property, in descending order)
    • ["fruit","ASC"] (sort by the 'fruit' property, in ascending order)
    • [["fruit","ASC"],["colour","DESC"]] (sort by the 'fruit' property first in ascending order and then by the 'colour' property in descending order)
    • Example Request:
Response

Status: 200

[
  {
    "_id": { "$oid": "4deeb1d9349c85523b000001" },
    "fruit": "orange",
    "colour": "orange"
  },
  {
    "_id": { "$oid": "4deeb1d9349c85523b000002" },
    "fruit": "kiwi",
    "colour": "brown",
    "size": "small"
  },
  {
    "_id": { "$oid": "4deeb1d9349c85523b000003" },
    "fruit": "banana",
    "colour": "yellow",
    "organic": true
  }
]

POST /db/collection

Add an item to a collection

The request data should contain a full representation of the item to create. This can be sent either as regular, url-encoded form data (i.e. Content-Type: application/x-www-form-urlencoded), or as a JSON-encoded string (i.e. Content-Type: application/json).

The server will respond with a full representation of the newly created object, with a server-generated _id if none was provided in the request data.

Request

POST /groceries/cart

{
  "fruit": "apple",
  "colour": "red",
  "variety": "Macintosh"
}
Response

Status: 201

{
  "_id": { "$oid": "4deeb1d9349c85523b000004" },
  "fruit": "apple",
  "colour": "red",
  "variety": "Macintosh"
}

PUT /db/collection/id

Replace an item in a collection

The request data should contain a full representation of the item to replace. This can be sent either as regular, url-encoded form data (i.e. Content-Type: application/x-www-form-urlencoded), or as a JSON-encoded string (i.e. Content-Type: application/json).

If the item with the given id does not yet exist, it will be automatically created. However this behaviour is subject to change in a future version (an additional parameter may be required to enable this "upsert" behaviour).

Request

PUT /groceries/cart/4deeb1d9349c85523b000004

{
  "fruit": "apple",
  "colour": "green",
  "variety": "Golen Delicious"
}
Response

Status: 200

{
  "_id": { "$oid": "4deeb1d9349c85523b000004" },
  "fruit": "apple",
  "colour": "green",
  "variety": "Golen Delicious"
}

PATCH /db/collection/id

Partially replace an item in a collection

Unlike a PUT, a PATCH request will only replace the given properties (instead of replacing the entire item).

The request data should contain a full representation of the item to replace. This can be sent either as regular, url-encoded form data (i.e. Content-Type: application/x-www-form-urlencoded), or as a JSON-encoded string (i.e. Content-Type: application/json).

If the item with the given id does not yet exist, the server will respond with 404 (Not Found).

Request

PATCH /groceries/cart/4deeb1d9349c85523b000004

{
  "colour": "orange"
}
Response

Status: 200

{
  "_id": { "$oid": "4deeb1d9349c85523b000004" },
  "fruit": "apple",
  "colour": "orange",
  "variety": "Golen Delicious"
}

DELETE /db/collection/id

Delete an item from a collection

Note that the request will succeed regardless of whether an item with the given id exists.

Request

DELETE /groceries/cart/4deeb1d9349c85523b000004

Response

Status: 200

{}