/rest-mongo

A JS ORM for both server and browser providing Rest server connect middleware

Primary LanguageJavaScriptGNU Affero General Public License v3.0AGPL-3.0

rest-mongo

A JS ORM for nodejs / mongo-db and/or the browser.

Intro

RestMongo works by letting you describe your data using a JSON schema and then provides you high level objects which can be created / updated / deleted / retrieved using an easy-to-use API. The core functionalities work on both node and the browser. There are different backends, wether you want to plug to a mongodb, a REST API, etc.

Examples

A Schema describing a person


var schema = {
  "Person": {
    resource: '/people',
    schema: {
      id: "Person",
      description: "someone, blablabla",
      type: "object",
       
      properties: {
        firstname: {type: "string"},
        friends: {type: "array", items: {"$ref": "Person"}},
        mother: {"$ref": "Person"}
      }
    },
    methods: {
      sayHello: function() {
        console.log("Hello, "+ this.firstname);
      }
    }
  }
};

The schema describes a document. It can have references or list of references to other documents. You can also associate methods to objects in the schema. Here, we will have the sayHello method available on Person objects.

Get a unit of work (we call it 'R'):


var rest_mongo = require("rest-mongo");
var mongo_backend = require('rest-mongo/mongo_backend');
var backend = mongo_backend.get_backend({db_name: 'db_name', username: "username", password:"password"});
var RFactory = rest_mongo.getRFactory(schema, backend);
var R = RFactory();

Get a new R every time you need to get a new context to work in (at every client request for example).

Additional schema

When creating a RFactory, you can specify an additional schema that will extend the base one. This is done so you can have properties or methods specific to server/browser side.


var server_schema = {
  "Person": {
    schema: {
      properties: {
        secret: {type: "string"}
      }
    },
    methods: {
      get_same_secrets: function(callback, fallback) {
        // Returns Persons with the same secret as me.
        this.R.Person.index({query: {secret: this.secret}},
                            callback, fallback);
      }
    }
  }
}

var RFactory = rest_mongo.getRFactory(schema, backend, {
  additional_schema: server_schema
});

Create and save an object into the DB


var lilly = new R.Person({firstname: "Lilly"});
lilly.sayHello();
lilly.save(function() {
  sys.puts("Lilly saved in DB with id " + lilly.id());
});

Get one or more objects from DB


R.Person.get({
 ids: lilly.id()
}, function(lilly2){
  // lilly and lilly2 are the same
});

Search in DB


R.Person.index({
 query: {firstname: "Lilly"}
}, function(data){
  var lilly = data[0];
});

Delete an object


lilly.delete_(function(){
  sys.puts('Lilly deleted from DB!');
}, function() {
  sys.puts('You can not delete Lily!');
});

Usage of references:


var harry = new R.Person({firstname: "Harry", mother: lilly});
harry.save(function() {
  sys.puts('Only the id of Lilly has been saved in harry.mother in DB.');
});

Update more than one object in once:


R.Person.update({
  ids: [lilly.id(), harry.id()], 
  data: {firstname: 'anonymous'}
}, function() {
  sys.puts("Voldemort cannot find them anymore...");
});

Save more than one object in once:


var p1 = new R.Person({firstname: 'Hermione'});
var p2 = new R.Person({firstname: 'Ron'});
R.save([p1, p2], function() {
  console.log('Now Harry has friends.')
}, function(error) {
  console.log('Harry has no friends, because of ', error);
});

Delete more than one object in once:


R.Person.remove({
  firstname: 'anonymous'
}, function() {
  console.log('There is no more anonymous person in DB.');
});

R.Person.remove({}, function() {
  console.log('No more person object in DB.');
}, function(error) {
  console.error('Could not remove all persons from DB.');
});

Connect middleware

rest-mongo also provides you with a connect middleware which can serve your data over a REST API using the provided schema.

Starting a REST server on the port 8888


var connector = rest_server.connector(RFactory, schema);
server = http.createServer(function(req, resp) {
  connector(req, resp, function() {
    res.writeHead(404, {}); res.end();
  });
});
server.listen(8888);

If is now possible to get the list of Person objects doing a GET HTTP request on localhost:8888/people

Authorization

It is possible to specify a third argument auth_check when calling the connector function. This argument should be a function. If provided, it will be called to check if rest-mongo can reply to the request or not. The function signature is:

auth_check(req, res, next, info)

  • req: nodejs req obj.
  • res: nodejs res obj.
  • next: to be called if ok to continue serving the request.
  • info: hash containing 'pathname', 'method', and 'data' attrs.

Installation

This version has been tested on:

node-mongodb-native and nodetk are vendorized through git submodules: $ git submodule update --init

To run the tests: nodetests Please have a look at the nodetk README file to install nodetk.

License

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.fsf.org/licensing/licenses/agpl-3.0.html