Giter Club home page Giter Club logo

node-restful's Introduction

build status

node-restful

Create awesome APIs using express.

Register mongoose resources and default RESTful routes are automatically made

var express = require('express'),
    bodyParser = require('body-parser'),
    methodOverride = require('method-override'),
    morgan = require('morgan'),
    restful = require('node-restful'),
    mongoose = restful.mongoose;
var app = express();

app.use(morgan('dev'));
app.use(bodyParser.urlencoded({'extended':'true'}));
app.use(bodyParser.json());
app.use(bodyParser.json({type:'application/vnd.api+json'}));
app.use(methodOverride());

mongoose.connect("mongodb://localhost/resources");

var Resource = app.resource = restful.model('resource', mongoose.Schema({
    title: String,
    year: Number,
  }))
  .methods(['get', 'post', 'put', 'delete']);

Resource.register(app, '/resources');

app.listen(3000);

Registers the following routes:

GET /resources
GET /resources/:id
POST /resources
PUT /resources/:id
DELETE /resources/:id

which do exactly what you think they do!

The best part is that restful.model returns a Mongoose model, so you can interact with it the same way that you're already accustomed to! (i.e. new Resource, Resource.findById, etc.)

Support

This library is currently supported through complaint driven development, so if you see something, have a feature request, open an issue and if it seems to jive with the mission of the library, I'll prioritize it.

Install

npm install node-restful

Usage

There is a good example application under examples/movies.

I will also show some features and use cases for them, how to set up routes, etc.

API

There are a few functions that are available after we register the mongoose schema. The first one we already saw.

.methods([...]) takes a list of methods that should be available on the resource. Future calls to methods will override previously set values To disallow delete operations, simply run

Resource.methods(['get', 'post', 'put'])

We can also run custom routes. We can add custom routes by calling .route(path, handler)

Resource.route('recommend', function(req, res, next) {
  res.send('I have a recommendation for you!');
});

This will set up a route at /resources/recommend, which will be called on all HTTP methods. We can also restrict the HTTP method by adding it to the path:

Resource.route('recommend.get', function(req, res, next) {
   res.send('GET a recommendation');
});
Resource.route('recommend', ['get', 'put', 'delete'], function(req, res, next) { ... });

Or do some combination of HTTP methods.

Now. Lets say we have to run arbitrary code before or after a route. Lets say we need to hash a password before a POST or PUT operation. Well, easy.

Resource.before('post', hash_password)
  .before('put', hash_password);
      
function hash_password(req, res, next) {
  req.body.password = hash(req.body.password);
  next();
}

Boy. That was easy. What about doing stuff after request, but before its sent back to the user? Restful stores the bundle of data to be returned in res.locals (see express docs). res.locals.status_code is the returned status code and res.locals.bundle is the bundle of data. In every before and after call, you are free to modify these are you see fit!

Resource.after('get', function(req, res, next) {
  var tmp = res.locals.bundle.title; // Lets swap the title and year fields because we're funny!
  res.locals.bundle.title = res.locals.bundle.year;
  res.locals.bundle.year = tmp;
  next(); // Don't forget to call next!
});
    
Resource.after('recommend', do_something); // Runs after all HTTP verbs

Now, this is all great. But up until now we've really only talked about defining list routes, those at /resources/route_name. We can also define detail routes. Those look like this

Resource.route('moreinfo', {
    detail: true,
    handler: function(req, res, next) {
        // req.params.id holds the resource's id
        res.send("I'm at /resources/:id/moreinfo!")
    }
});

I don't think this is the prettiest, and I'd be open to suggestions on how to beautify detail route definition...

And that's everything for now!

Built-in Filters

Node-restful accepts many options to manipulate the list results. These options can be added to your request either via the querystring or the POST body. They are passed into the mongoose query to filter your resultset.

Selecting the entity-properties you need

If you only need a few properties instead of the entire model, you can ask the service to only give just the properties you need:

A GET request to /users/?select=name%20email will result in:

[
    {
        "_id": "543adb9c7a0f149e3ac29438",
        "name": "user1",
        "email": "[email protected]"
    },
    {
        "_id": "543adb9c7a0f149e3ac2943b",
        "name": "user2",
        "email": "[email protected]"
    }
]

Limiting the number and skipping items

When implementing pagination you might want to use skip and limit filters. Both do exactly what their name says and just skip given amount of items or limit to a set amount of items.

/users/?limit=5 will give you the first 5 items
/users/?skip=5 will skip the first 5 and give you the rest
/users/?limit=5&skip=5 will skip the first 5 and then give you the second 5

Sorting the result

Getting a sorted list is as easy as adding a sort querystring parameter with the property you want to sort on. /users/?sort=name will give you a list sorted on the name property, with an ascending sort order.

Changing the sort order uses the same rules as the string notation of mongoose's sort filter. /users/?sort=-name will return the same list as before with a descending sort order.

Filtering the results

Sometimes you just want to get all people older than 18, or you are want to get all people living in a certain city. Then you would want to use filters for that. You can ask the service for equality, or values greater or less than, give it an array of values it should match to, or even a regex.

Filter Query Example Description
equal equals /users?gender=male or /users?gender__equals=male both return all male users
not equal ne /users?gender__ne=male returns all users who are not male (female and x)
greater than gt /users?age__gt=18 returns all users older than 18
greater than or equal to gte /users?age__gte=18 returns all users 18 and older (age should be a number property)
less than lt /users?age__lt=30 returns all users age 29 and younger
less than or equal to lte /users?age__lte=30 returns all users age 30 and younger
in in /users?gender__in=female,male returns all female and male users
nin nin /users?age__nin=18,30 returns all users with age other than 18 or 30
Regex regex /users?username__regex=/^baugarten/i returns all users with a username starting with baugarten

Populating a sub-entity

When you have setup a mongoose Schema with properties referencing other entities, you can ask the service to populate them for you.

A GET request to /users/542edff9fffc55dd29d99346 will result in:

{
    "_id": "542edff9fffc55dd29d99346",
    "name": "the employee",
    "email": "[email protected]",
    "boss": "542edff9fffc55dd29d99343",
    "__v": 0
}

A GET request to /users/542edff9fffc55dd29d99346?populate=boss will result in:

{
    "_id": "542edff9fffc55dd29d99346",
    "name": "the employee",
    "email": "[email protected]",
    "boss": {
        "_id": "542edff9fffc55dd29d99343",
        "name": "the boss",
        "email": "[email protected]",
        "__v": 0
    },
    "__v": 0
}

Contributing

You can view the issue list for what I'm working on, or contact me to help!

Just reach out to me

MIT License

Copyright (c) 2012 by Ben Augarten

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

node-restful's People

Contributors

adrichman avatar baugarten avatar brunobraga avatar canac avatar gpbmike avatar karvapallo avatar maximeborges avatar nicoespeon avatar raisen avatar rlebron88 avatar sanderhouttekier avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-restful's Issues

"Cannot call method 'toString' of undefined" when using routes

Following code caused the error in http.js - statusCode is undefined.
http.js:1181
var statusLine = 'HTTP/1.1 ' + statusCode.toString() + ' ' +

It looks like the handler is never called.

Project.route("questions", {
    handler: function(req, res, next, err, model) { 
         res.send(model.questions);
        return next();
    },
    detail: true,
    methods: ['get']
});

Project is working fine with all methods.

[email protected] node_modules/node-restful
โ””โ”€โ”€ [email protected] ([email protected], [email protected], [email protected], [email protected], [email protected])

Custom error response code and message

Hello, right now I see that response codes for errors are hardcoded to the route. This can cause confusion when there is an internal error because the client thinks it is a bad request.

In addition, the error message does not serialize correctly when passing an Error object, which several other middlewares require.

I have locally hacked

exports.respondOrErr = function(res, errStatusCode, err, statusCode, content) {
  if (err) {
    exports.respond(res, err.statusCode || errStatusCode, err.message || err);
  } else {
    exports.respond(res, statusCode, content);
  }
};

and then am passing an Error like so

var error = new Error(err);
error.statusCode = 500;
next(error); 

Is this satisfactory/best practice? Didn't feel like making a pull request for such a minor change without knowing that the pattern was acceptable.

Thanks

Use same routing API as express

Should be able to define userroutes by using

model.get('path_to_route', true, function(req, res, next) {})
mode.get('path_to_another_route', { detail: true }, function(req, res, next) {});

and other HTTP Verbs

Test Suite

Comprehensive test suite

I just added a bare bones one that tests some basic routing

More comprehensive tests for advanced routing, new features, custom options needed

User defined routes options

Options for user defined routes:

http methods
singleObject (better name) // whether to require a filter for one object for the route
...
...

and more?

Update tutorial

Please update your tutorial.

You code is well but i lost 3 day for understand, because your tutorial is too old.

for help

var express = require('express'),
    mongoose = require('mongoose'),
    restful = require('../');
// Make a new Express app
var app = module.exports = express();

// Connect to mongodb
mongoose.connect("mongodb://localhost/restful");

// Use middleware to parse POST data and use custom HTTP methods
app.use(express.bodyParser());
app.use(express.methodOverride());

var hashPassword = function(req, res, next) {
  if (!req.body.password)
    return next({ status: 400, err: "No password!" }); // We can also throw an error from a before route
  req.body.password = bcrypt.hashSync(req.body.password, 10); // Using bcrypt
  return next(); // Call the handler
}

var sendEmail = function(req, res, next) {
  // We can get the user from res.bundle and status code from res.status and
  // trigger an error by calling next(err) or populate information that would otherwise be miggins
  next(); // I'll just pass though
}

var User = restful.model( "users", mongoose.Schema({
    username: 'string',
    password_hash: 'string',
  }))
  .methods(['get', 'put', 'delete', {
    type: 'post',
    before: hashPassword, // Before we make run the default POST to create a user, we want to hash the password (implementation omitted)
    after: sendEmail, // After we register them, we will send them a confirmation email
  }]);

User.route("notes", {
  handler: function(req, res, next) { // we get err and model parameters on detail routes (model being the one model that was found)
    Note.Model.find({ creator: req.params.id }, function(err, list) {
      if (err) return next({ status: 500, err: "Something went wrong" });
      //res.status is the status code
      res.locals.status_code = 200;

      // res.bundle is what is returned, serialized to JSON
      res.locals.bundle = list;
      return next();
    });
  },
  detail: true, // detail routes operate on a single instance, i.e. /user/:id
  methods: ['get'], // only respond to GET requests
});

User.register(app, '/user'); // Register the user model at the localhost:3000/user

var validateUser = function(req, res, next) {
  if (!req.body.creator) {
    return next({ status: 400, err: "Notes need a creator" });
  }
  User.Model.findById(req.body.creator, function(err, model) {
    if (!model) return next(restful.objectNotFound());
    return next();
  });
}

var Note = restful.model("note", mongoose.Schema({
    title: { type: 'string', required: true},
    body: { type: 'string', required: true},
    creator: { type: 'ObjectId', ref: 'user', require: true},
  }))
  .methods(['get', 'delete', { type: 'post', before: validateUser }, { type: 'put', before: validateUser }]);

Note.register(app, '/note');


app.listen(3000);

HTML Template generation

It would be cool to be able to generate default HTML templates for the API endpoints using node-restful. I.e. given a model declaration, generate the form view, detail view, etc

I also need to write documentation for how HTML templates are used and rendered

non-strict routes

Should add an option to add non-strict routes for

/<model_name>/new // renders the create form
/<model_name>/:id/edit // renders the edit form
/<model_name>/:id/destroy // instead of DELETE
/<model_name>/:id/update // instead of PUT

Expose Mongoose Options

Should be able to set default Mongoose options for updates, deletes, and inserts on Models

Feature Question

Is there support for nested models ?

Is there support for auth ?

I'm about to write a library similar to yours though I'll be adding these

Best practice for filter and populating?

Hey,

I just wanted to ask if there is a better approach than mine for filtering results based on conditions:

methods.before('get', function (req, res, next) {
    req.quer._conditions.user_id = req.session.user._id;
    next();
});

And the second question, how would I implement populating on refs? This doesn't work:

req.quer.options.populate.circuits = ['name'];

Greetings Kersten

Not able to specify getDetail as a method

Hello, i am building a very specific api and i would like to disable the list all route (get) for just the detail one (getDetail). First it was working, and then with no code change it just stopped working.

Endpoint generation for nested models

If a model has an objectID,
expose an endpoint by that object's name that just returns that object or object_id that returns the id

movies: {
  title: String,
  user: ObjectId,
}

You can access it at /movies/:id/user or /movies/:id/user_id

Fix Routing

I have a feeling my routing is broken, in that it doesn't get all of the error cases right, the filter string is kind of wonky, etc. It would be better done, safer, DRYer to use express routing or a third party

Either use app.get, app.post, etc. or refactor routing code to a dedicated router or outsource routing

The problem with using express routing is that before routes wouldn't be able to be declared after the model is registered. This shouldn't actually be a problem, and we can raise a warning if this happens (all filters should be declared before registering a model anyway), so I'm leaning towards using express routing

TypeError: object is not a function

This is what I get when trying to run the example:

var app = restful();
      ^
TypeError: object is not a function
    at Object.<anonymous> (........................................js:4:11)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.runMain (module.js:492:10)
    at process.startup.processNextTick.process._tickCallback (node.js:244:9)

Case insensitive

Hello, how would I do a case insensitive filter?

?key__regex=value

will not work because there is no way to specify regex options in the query from what I can tell.

Thanks,

Chris

app.use

Change to app.use(path, Resource) instead of calling Resource.register(app, path)

Test Suite

Fix test suite to have better fixtures and clean up before and after each test better

Also mirror express in that it uses the example apps as the acceptance tests

Multiple Middleware

I have been searching previous issues and have not been able to find an answer to a question I have.

Is it possible to register multiple middleware on a single HTTP action.

For example:

var resource ...

resource.before('get', doSomething)
     .before('get', doAnotherThing)

Not registering Schema for model

I've got my models in folders, for example:

// Meeting model

var mongoose = require('mongoose')
  , restful = require('node-restful');

var meetingSchema = mongoose.Schema({
  date: Date,
  location: String,
  committee: mongoose.Schema.ObjectId
});

module.exports = restful.model('Meeting', meetingSchema).methods(['get','post']);

and then

Meeting = require("./models/meeting.js");
Meeting.register(app, '/api/meetings');

However, for some reason I'm getting a MissingSchemaError: Schema hasn't been registered for model "Committee". error. Any ideas why?

Filter by array

I'd like query a field with an array of values.

For example

/fruits?species=apple,orange

/fruits?species=apple%20orange

/fruits?species=[apple,orange]

/fruits__ne?species=apple,orange

/fruits__all?species=apple,orange

/fruits__any?species=apple,orange

data.toLowerCase on non string in model.js

Running into this with newer versions:

model.js:

function coerceData(data) {
// Assume data is a string
if (data.toLowerCase() === 'true') {
return true;
} else if (data.toLowerCase() === 'false') {
return false;
}
return data;
};

TypeError: Cannot call method 'toLowerCase' of null
Other mixed errors when the value is not a string.

Fix:

function coerceData(data) {
// Assume data is a string
if (data && data.toLowerCase && data.toLowerCase() === 'true') {
return true;
} else if (data && data.toLowerCase && data.toLowerCase() === 'false') {
return false;
}
return data;
};

BTW -- Thanks for the great little module.

Perhaps this should be a plugin for express?

i.e.

var express = require('express'),
      restful = require('restful');
var app = express();

var movie = restful.Model({
  title: "movies",
  methods: ['get', 'post', 'put', 'delete'],
  schema: mongoose.Schema({
    title: 'string',
    year: 'number',
  }),
});

movie.register(app);

app.listen(3000);

When using node-restful with AngularJS, $resource.query() not working correctly with single objects

When using AngularJS, it is possible to create a quick and dirty interface to a REST API by doing something like:

var Objs = $resource('/api/objects/:id');

This by default creates five built-in actions:

{ 'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'} };

However, node-restful seems to ignore the "isArray: true" portion of the query action and returns:

{ an object }

instead of:

[ { an object } ]

when there is only one object to be sent. Proper behavior should be the latter.

compatible with?

is only compatible with mongodb or work with another like couchdb, hadoop or something?

is compatible with an orms like postgresql, mysql, oracle, sqlserver or something?

thanks

Model.addSchemaRoutes

Was looking at lib/models.js at Model.addSchemaRoutes:

if (schemaType.options.type === 'ObjectId') {
// Right now, getting nested models is the only operation supported
['get'].forEach(function(method) {
self.route(pathName, method , {
handler: handlers[method + 'Path'].call(self, pathName),
detail: true
});
});
}

If I'm reading this correctly, it should add getters for referenced ObjectId types, but the eval here fails:
if (schemaType.options.type === 'ObjectId')

When the schema is defined as:

owner: { type: ObjectId, ref: 'User' }

What does work:

  if (schemaType.instance === 'ObjectID') {

Changing to this evaluation provides the getter for the linked object.

Update does not work

Hey again,

I just wanted to update a model without the rest interface.

User.update({_id: '51d299b48e8ab7da3a000003'}, {
    name: 'Test 1'
}, function (err) {
    console.log(arguments);
});

But this do not work. The callback never gets called.

Could you help me with that? I saw in the test that you are using Resource.Model to get the original mongoose model, but that doesn't work too. Could it be that the tests are not up to date?

Default response format

Should add option to specify default response formats, either HTML, JSON, XML and support for XML in general

before and after filters for multiple routes/whole resources

Set up a before/after route for the entire resource or path in resource. i.e.

model = restful.model(..);
model.before('*', function(req, res, next) {..});
model.before('path.*', function(req, res, next) {});
model.before('path.*', ['get', 'post'], function(req, res, next) {});

Can do this using express's wildcard routing fairly easily but the internal representation is harder

PUT an element to an array

Given this model:

var Task = app.task = restful.model('task', mongoose.Schema({
    title: { type: 'string', require: true },
    body: { type: 'string', require: true },
    user_id: { type: 'ObjectId', ref: 'user', require: true },
    comments: [{
      body: { type: 'string', require: true },
      votes: {
        user_id: { type: 'ObjectId', ref: 'user' },
        score: { type: 'number' } 
      },
      author: { type: 'ObjectId', ref: 'user' },
    }],
  }))
  .methods(['get', 'delete', 'put', 'post' ]);

Is this possible to PUT a Comment to an existing Task?

I was looking to use an URL like /tasks/:id:/comments and PUT a comment object to it.

Update tutorial

Please update your tutorial.

You code is well but i lost 3 day for understand, because your tutorial is too old.

for help

var express = require('express'),
mongoose = require('mongoose'),
restful = require('../');
// Make a new Express app
var app = module.exports = express();

// Connect to mongodb
mongoose.connect("mongodb://localhost/restful");

// Use middleware to parse POST data and use custom HTTP methods
app.use(express.bodyParser());
app.use(express.methodOverride());

var hashPassword = function(req, res, next) {
if (!req.body.password)
return next({ status: 400, err: "No password!" }); // We can also throw an error from a before route
req.body.password = bcrypt.hashSync(req.body.password, 10); // Using bcrypt
return next(); // Call the handler
}

var sendEmail = function(req, res, next) {
// We can get the user from res.bundle and status code from res.status and
// trigger an error by calling next(err) or populate information that would otherwise be miggins
next(); // I'll just pass though
}

var User = restful.model( "users", mongoose.Schema({
username: 'string',
password_hash: 'string',
}))
.methods(['get', 'put', 'delete', {
type: 'post',
before: hashPassword, // Before we make run the default POST to create a user, we want to hash the password (implementation omitted)
after: sendEmail, // After we register them, we will send them a confirmation email
}]);

User.route("notes", {
handler: function(req, res, next) { // we get err and model parameters on detail routes (model being the one model that was found)
Note.Model.find({ creator: req.params.id }, function(err, list) {
if (err) return next({ status: 500, err: "Something went wrong" });
//res.status is the status code
res.locals.status_code = 200;

  // res.bundle is what is returned, serialized to JSON
  res.locals.bundle = list;
  return next();
});

},
detail: true, // detail routes operate on a single instance, i.e. /user/:id
methods: ['get'], // only respond to GET requests
});

User.register(app, '/user'); // Register the user model at the localhost:3000/user

var validateUser = function(req, res, next) {
if (!req.body.creator) {
return next({ status: 400, err: "Notes need a creator" });
}
User.Model.findById(req.body.creator, function(err, model) {
if (!model) return next(restful.objectNotFound());
return next();
});
}

var Note = restful.model("note", mongoose.Schema({
title: { type: 'string', required: true},
body: { type: 'string', required: true},
creator: { type: 'ObjectId', ref: 'user', require: true},
}))
.methods(['get', 'delete', { type: 'post', before: validateUser }, { type: 'put', before: validateUser }]);

Note.register(app, '/note');

app.listen(3000);

Better Handler Encapsulation

There should be a set of data that is sufficient for handling a request that isn't intrinsically ties to request and response objects. This will make returning data more clear as well as give the ability to call handlers from other code.

I.e. a certain route might be able to call the get, put, and delete handlers of an object at different times.

def get(filters)

def post(data)

def put(filters, data)

def delete(filters)

Fails on DELETE with no data available

Example :
client.registerMethod('deleteXyz',baseUrl + 'xyz/${id}', 'DELETE');
..
client.methods.deletePool({
headers : {'Accept' : 'application/json'},
path : {id:id} },callback);

Fix : line 289 in node-rest-client.js :
... else if (self.isJSON(content)){
debug("typeof data es ", typeof data);
if(data) {
callback(JSON.parse(data), res);
} else {
callback(null,res);
} ...

Do you have the ability to offset/limit results?

I tried browsing the source to look for it because it's not documented anywhere, but I didn't see anything on that. This is particularly essential for large data-sets.

I was playing around with node-restful, considering it for an API that I'm building, but I don't want anyone to be able to fetch more than 50 results at a time. Right now it will load the entire collection.

Return a mongoose.Model instead of our own Model

It might make more sense to instead have restful.Model be a method that returns a mongoose Model with our prototype. That way you could actually use the new operator on the model returned by the initial call, and all the other methods users might want to use from mongoose

Expose CRUD operations

Expose common CRUD operations to user defined routes through

model = restful.model(...)
model.route('anotherget', {
    detail: true,
    handler: function(req, res, next) {
        model.get(req.params.id, function(err, model) {..}) 
        model.post(req.params.id, { data: value }, function(err, model) {..});
    }
});

Stupid example, but this could be useful

Support for virtual properties?

My schema includes a virtual (read-only) property getter, which means I have to run .toObject() on it before sending it to the client side. Is there any provision to do this now?

If not, what would it take? More to the point, what form would it take? Would there be a flag to enable it, or would it be "just part of the service" (i.e., convert it right before sending it out)?

In the meantime, I should be able to handle it in an .after(), but that could get ugly later if I add another one that's expecting res.locals.bundle to be a(n array of) Mongoose object(s).

Mongoose remove middleware not invoked

I would like to know if executing a DELETE action on an endpoint will trigger the 'remove' event on the model associated with my Node Restful resource.

I have all my mongoose middleware set up to remove associated models when the parent model is removed, but nothing happens to those associated models when the resource's model is removed.

Expose .before and .after

Should be able to do

var Model = new restful.Model(...);
Model.before('get', function(req, res, next) {...});
Model.after('login', function(req, res, next) {...});  

Override resource 'index' handler

Hey @baugarten, great work on this lib!

Is there a way to override the handler of specific endpoints on this object?
For instance, for listing all of a certain resource i would like to show only a couple of fields and paginating

Multiple Response formats

Should respond to a GET or POST parameter for format=json,xml,html

HTML responses will rely on express's internal templating and render templates from a default directory, which will be a parameter in model instantiation i.e. /api/resourcename/index.html, detail.html, new.html, edit.html, possibly too with put.html, delete.html to confirm updates or deletes, maybe there is a use case.

HTML responses will also open up the need for new routes, i.e.
id/new
id/edit

These routes are optional

how to use jsan in post ?

I am new to node, was looking at your resources example it worked fine but
I had to pass "title=testing&year=1992"

what do i have to so that it accept json object like '{"title" : "testing","year" : "1992"}'

Filters

Need support for more mongodb filters in the url or as get parameters (should be flexible)

i.e.

GET /<resource_name>/filter&filter2&filter3/
should be interchangeable with
GET /<resource_name>/?filter&filter2&filter3

Possibly also process post parameters:
i.e. POST

data: {
  filters: [
    filter1,
    filter2
    filter3
  ]
}

Also consider
field getters:
/movies/:id/title,reviews
/movies/:id/year,meta.director

Handler not running when arguments.length>3

I took an example from your readme and added two arguments that I needed:
(based on http://benaugarten.com/blog/2013/01/31/restful-a-better-rest-api-using-node-dot-js-with-express/)

Resource.route('moreinfo', {
    detail: true,
    handler: function(req, res, next, err, model) { //ADDED err and model
        // req.params.id holds the resource's id
        res.send("I'm at /resources/:id/moreinfo!")
    }
});

The handler never runs and therefore the situation with broken status_code occurs (as in #43)

the next() handler in express looks like this:

function callbacks(err) {
  var fn = route.callbacks[i++];
  try {
    if ('route' == err) {
      nextRoute();
    } else if (err && fn) {
      if (fn.length < 4) return callbacks(err);
      fn(err, req, res, callbacks);
    } else if (fn) {
      if (fn.length < 4) return fn(req, res, callbacks);
      callbacks();
    } else {
      nextRoute(err);
    }
  } catch (err) {
    callbacks(err);
  }
}

I guess the tutorial needs an update, because the err and model are not coming back I guess.
What is the currently correct way to interact with element's model? Should I query for it in route handler now?

My current code looks like this:

Project.route('pages', ['get'], {
    detail: true,
    handler: function(req, res, next) {
        // req.params.id holds the resource's id
        Project.findById(req.params.id, function(err, model) {
            if (!model) {
                return next(restful.objectNotFound());
            }
            res.send(model.pages);
        });

    }
});

But I'm not sure if I'm not quering the same thing twice

DELETE 404

When making a DELETE request using RESTANGULAR (AngularJS), I get

DELETE http://localhost:3000/resources 404 (Not Found)

even though my model clearly states that this method is allow:

var Resource = app.resource = restful.model('resource', mongoose.Schema({
    title: 'string',
    year: 'number',
})).methods(['get', 'post', 'put', 'delete']);

Resource.register(app, '/resources');

What should I check? Please advise.

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.