package.json
{
"dependencies": {
"express-restify-mongoose": "^2.0.0",
"mongoose": "^4.0.0"
}
}
From the command line
npm install express-restify-mongoose --save
This snippet…
var express = require('express')
var bodyParser = require('body-parser')
var methodOverride = require('method-override')
var mongoose = require('mongoose')
var restify = require('express-restify-mongoose')
var app = express()
var router = express.Router()
app.use(bodyParser.json())
app.use(methodOverride())
mongoose.connect('mongodb://localhost/database')
restify.serve(router, mongoose.model('Customer', new mongoose.Schema({
name: { type: String, required: true },
comment: { type: String }
})))
app.use(router)
app.listen(3000, function () {
console.log('Express server listening on port 3000')
})
…automatically generates those endpoints.
GET http://localhost/api/v1/Customers/count
GET http://localhost/api/v1/Customers
PUT http://localhost/api/v1/Customers
POST http://localhost/api/v1/Customers
DELETE http://localhost/api/v1/Customers
GET http://localhost/api/v1/Customers/:id
GET http://localhost/api/v1/Customers/:id/shallow
PUT http://localhost/api/v1/Customers/:id
POST http://localhost/api/v1/Customers/:id
DELETE http://localhost/api/v1/Customers/:id
var request = require('request')
request({
url: '/api/v1/Model',
qs: {
query: JSON.stringify({
$or: [{
name: '~Another'
}, {
$and: [{
name: '~Product'
}, {
price: '<=10'
}]
}],
price: 20
})
}
})
All the following parameters (sort, skip, limit, query, populate, select and distinct) support the entire mongoose feature set.
When passing values as objects or arrays in URLs, they must be valid JSON
GET /Customers?sort=name
GET /Customers?sort=-name
GET /Customers?sort={"name":1}
GET /Customers?sort={"name":-1}
GET /Customers?skip=10
Only overrides options.limit
if the queried limit is lower
GET /Customers?limit=10
Supports all operators ($regex, $gt, $gte, $lt, $lte, $ne, etc.) as well as shorthands: ~, >, >=, <, <=, !=
GET /Customers?query={"name":"Bob"}
GET /Customers?query={"name":{"$regex":"^(Bob)"}}
GET /Customers?query={"name":"~^(Bob)"}
GET /Customers?query={"age":{"$gt":12}}
GET /Customers?query={"age":">12"}
GET /Customers?query={"age":{"$gte":12}}
GET /Customers?query={"age":">=12"}
GET /Customers?query={"age":{"$lt":12}}
GET /Customers?query={"age":"<12"}
GET /Customers?query={"age":{"$lte":12}}
GET /Customers?query={"age":"<=12"}
GET /Customers?query={"age":{"$ne":12}}
GET /Customers?query={"age":"!=12"}
Works with create, read and update operations
GET/POST/PUT /Invoices?populate=customer
GET/POST/PUT /Invoices?populate={"path":"customer"}
GET/POST/PUT /Invoices?populate=[{"path":"customer"},{"path":"products"}]
_id
is always returned unless explicitely excluded
GET /Customers?select=name
GET /Customers?select=-name
GET /Customers?select={"name":1}
GET /Customers?select={"name":0}
GET /Customers?distinct=name
restify.serve(router, model[, options])
router: express.Router() instance (Express 4), app object (Express 3) or server object (restify)
model: mongoose model
options: object typedefaultversion
string/api
Path to prefix to the REST endpoint
string/v1
API version that will be prefixed to the rest path. If prefix or version contains /:id
, then that will be used as the location to search for the id
Generates /api/v1/Entities/:id/Model
and /api/v1/Entities/Model
for all pertinent methods
version: '/v1/Entities/:id'
string_id
findById
will query on the given property
booleanfalse
Enable support for restify instead of express
booleantrue
Automatically pluralize model names using inflection
booleanfalse
Whether to call .toLowerCase()
on model names before generating the routes
stringmodel name
Endpoint name
stringprimary2.3
Determines the MongoDB nodes from which to read. Read more
boolean|stringfalse2.4
When set to true
, executes a count query on GET /Model
requests that sets limit and skip to 0 and sets the result in the
X-Total-Count
header. It can also be set to a string to allow for a custom header.
Boolean
totalCountHeader: true
Response:
Headers: {
'X-Total-Count': 5
}
String
totalCountHeader: 'X-Custom-Count-Header'
Response:
Headers: {
'X-Custom-Count-Header': 5
}
array
Array of fields which are only to be returned by queries that have private access
Defined in options
private: ['topSecret', 'fields']
Defined in mongoose schema
new Schema({
topSecret: { type: String, access: 'protected' },
fields: { type: String, access: 'protected' }
})
array
Array of fields which are only to be returned by queries that have private or protected access
Defined in options
protected: ['somewhatSecret', 'keys']
Defined in mongoose schema
new Schema({
somewhatSecret: { type: String, access: 'protected' },
keys: { type: String, access: 'protected' }
})
booleantrue
Whether or not mongoose should use .lean()
to convert results to plain old JavaScript objects. This is bad for performance, but allows returning virtuals, getters and setters.
booleantrue
Whether to use findOneAndUpdate or first findById and then save, allowing document middleware to be called. For more information regarding mongoose middleware, read the docs.
booleantrue
Whether to use findOneAndRemove or first findById and then remove, allowing document middleware to be called. For more information regarding mongoose middleware, read the docs.
function (req, res, next)2.0
Middleware that runs before preCreate, preRead, preUpdate and preDelete.
preMiddleware: function (req, res, next) {
performAsyncLogic(function (err) {
next(err)
})
}
function (req, res, next)2.1
Middleware that runs before creating a resource
preCreate: function (req, res, next) {
performAsyncLogic(function (err) {
next(err)
})
}
function (req, res, next)2.1
Middleware that runs before reading a resource
preRead: function (req, res, next) {
performAsyncLogic(function (err) {
next(err)
})
}
function (req, res, next)2.1
Middleware that runs before updating a resource
preUpdate: function (req, res, next) {
performAsyncLogic(function (err) {
next(err)
})
}
new in 2.2
When findOneAndUpdate
is disabled, the document is made available which is useful for authorization as well as setting values
findOneAndUpdate: false,
preUpdate: function (req, res, next) {
if (req.erm.document.user !== req.user._id) {
return res.sendStatus(401)
}
req.erm.document.set('lastRequestAt', new Date())
next()
}
function (req, res, next)2.1
Middleware that runs before deleting a resource
preDelete: function (req, res, next) {
performAsyncLogic(function (err) {
next(err)
})
}
new in 2.2
When findOneAndRemove
is disabled, the document is made available which is useful for authorization as well as performing non-destructive removals
findOneAndRemove: false,
preDelete: function (req, res, next) {
if (req.erm.document.user !== req.user._id) {
return res.sendStatus(401)
}
req.erm.document.deletedAt = new Date()
req.erm.document.save().then(function (doc) {
res.sendStatus(204)
}, function (err) {
options.onError(err, req, res, next)
})
}
function (req[, done])
Returns or yields ‘private’, ‘protected’ or ‘public’. It is called on GET, POST and PUT requests and filters out the fields defined in private and protected
Sync
access: function (req) {
if (req.isAuthenticated()) {
return req.user.isAdmin ? 'private' : 'protected'
} else {
return 'public'
}
}
Async
access: function (req, done) {
performAsyncLogic(function (err, result) {
done(err, result ? 'public' : 'private')
})
}
function (model, req, done)
Allows request specific filtering
contextFilter: function (model, req, done) {
done(model.find({
user: req.user._id
}))
}
function (req, res, next)2.0
Middleware that runs after successfully creating a resource
postCreate: function (req, res, next) {
var result = req.erm.result // object
var statusCode = req.erm.statusCode // 201
performAsyncLogic(function (err) {
next(err)
})
}
function (req, res, next)2.0
Middleware that runs after successfully reading a resource
postRead: function (req, res, next) {
var result = req.erm.result // object / array
var statusCode = req.erm.statusCode // 200
performAsyncLogic(function (err) {
next(err)
})
}
function (req, res, next)2.0
Middleware that runs after successfully updating a resource
postUpdate: function (req, res, next) {
var result = req.erm.result // object
var statusCode = req.erm.statusCode // 200
performAsyncLogic(function (err) {
next(err)
})
}
function (req, res, next)2.0
Middleware that runs after successfully deleting a resource
postDelete: function (req, res, next) {
var result = req.erm.result // undefined
var statusCode = req.erm.statusCode // 204
performAsyncLogic(function (err) {
next(err)
})
}
function (req, res)
Function used to output the result
outputFn: function (req, res) {
res.status(req.erm.statusCode).json(req.erm.result)
}
function (req, res, next)2.0
Middleware that is called after output, useful for logging
postProcess: function (req, res, next) {
console.log(`${req.method} ${req.path} request completed with response code ${req.erm.statusCode}`)
}
function (err, req, res, next)send the entire mongoose error
Function used to output an error
onError: function (err, req, res, next) {
next(err)
}
restify.defaults(options)
options: same as above, sets this object as the defaults for anything served afterwards