arrest v13.2.4
arrest
Swagger REST framework for Node.js, with support for MongoDB and JSON-Schema
Arrest lets you write RESTful web services in minutes. It automatically generates a Swagger description of the API and support input validation using JSON-Schemas.
Highlight features:
- Compatible with Express 4.x
- Implements simple CRUD semantics on MongoDB
- Supports querying object with the RQL syntax
- Input validation with JSON-Schema
- Oauth2 scope checks per operation
Note for 1.3 users: arrest 3.x is a complete rewrite of the old module and it's not backwards compatible.
How to Install
npm install arrest
Super Simple Example
The following sample application shows how to create a simple REST API, using a MongoDB collection as the data store. In the sample, the path /tests is linked to a tests collection on a MongoDB instance running on localhost:
const arrest = require('arrest');
const api = new arrest.API();
api.addResource(new arrest.MongoResource('mongodb://localhost:27017', { name: 'Test' }));
api.listen(3000);
The Swagger specification of the API you just created is available at http://localhost:3000/swagger.json
Now you can query your data collection like this:
curl "http://localhost:3000/tests"
You can add a new item:
curl "http://localhost:3000/tests" -H "Content-Type: application/json" -X POST -d '{ "name": "Jimbo", "surname": "Johnson" }'
You can query a specific item by appeding the identifier of the record (the _id attribute):
curl "http://localhost:3000/tests/51acc04f196573941f000002"
You can update an item:
curl "http://localhost:3000/tests/51acc04f196573941f000002" -H "Content-Type: application/json" -X PUT -d '{ "name": "Jimbo", "surname": "Smith" }'
And finally you can delete an item:
curl "http://localhost:3000/tests/51acc04f196573941f000002" -X DELETE
Creating an API
An API is a collection of Resources, each supporting one or more Operations.
In arrest you create an API by creating an instance of the base API
class or of a derived class.
You then add instances of the Resource
class or a derived one. Each resource contains its supported Routes
, that is
a collection of instances of classes derived from the abstract Operation
, which represents an operation to be executed
when an HTTP method is called on a path.
The following code demonstrates this three level structure:
const arrest = require('arrest');
const api = new arrest.API();
const operation1 = function(req, res, next) {
res.json({ data: 'this is operation 1' });
}
const operation2 = function(req, res, next) {
res.json({ data: 'this is operation 2' });
}
const operation3 = function(req, res, next) {
res.json({ data: 'this is operation 3' });
}
const resource1 = new arrest.Resource({
name: 'SomeResource',
routes: {
'/': {
get: operation1,
post: operation2
},
'/some-path': {
put: operation3
}
}
})
api.addResource(resource1);
api.listen(3000);
The API above supports the following operations:
GET
onhttp://localhost/some-resources
POST
onhttp://localhost/some-resources
PUT
onhttp://localhost/some-resources/some-path
Please note how the some-resources path was automatically constructed using the name of the resource SomeResource
, making
it plural and converting the camelcase in a dash-separated name. This default behaviour can be changed specifying the
namePlural and path when creating the resource (e.g. new Resource({ name: 'OneResource', namePlural: 'ManyResources', path: 'my_resources' })
)
Another other way to produce the same result is:
const arrest = require('arrest');
const api = new arrest.API();
const resource1 = new arrest.Resource({ name: 'SomeResource' });
resource1.addOperation('/', 'get', function(req, res, next) {
res.json({ data: 'this is operation 1' });
});
resource1.addOperation('/', 'post', function(req, res, next) {
res.json({ data: 'this is operation 2' });
});
resource1.addOperation('/some-path', 'put', function(req, res, next) {
res.json({ data: 'this is operation 3' });
});
api.addResource(resource1);
api.listen(3000);
In real world applications, where resources and operation are in fact more complex, you will want to create class that extend the basic classes in arrest, like in the next example:
const arrest = require('arrest');
class MyOperation extends arrest.Operation {
constructor(resource, path, method) {
super('op1', resource, path, method);
}
handler(req, res, next) {
res.json({ data: 'this is a custom operation' });
}
}
class MyResource extends arrest.Resource {
constructor() {
super();
this.addOperation(new MyOperation(this, '/', 'get'));
}
}
class MyAPI extends arrest.API {
constructor() {
super({
info: {
title: 'This is a custom API',
version: '0.9.5'
}
});
this.addResource(new MyResource());
}
}
const api = new MyAPI();
api.listen(3000);
The API above supports GET
s on http://localhost/my-resources
(note how the path was in this case constructed automatically
from the name of the class MyResource).
By the default, arrest APIs add a special route /swagger.json
that returns the Swagger description of the API: the Swagger
object is populated with the properties of the API object, Resources are converted into Swagger Tags and Operations are
mapped to Swagger Operations.
Data validation
arrest supports JSON-Schema for data validation. Validation rules are set using the Swagger specification. For instance,
the following code show how to validate the body of a POST
and the query paramters of a GET
:
class MyOperation1 extends arrest.Operation {
constructor(resource, path, method) {
super('op1', resource, path, method);
this.setInfo({
parameters: [
{
name: 'body',
in: 'body',
required: true,
schema: {
type: 'object',
required: [ 'name' ],
additionalProperties: false,
properties: {
name: {
type: 'string'
},
surname: {
type: 'string'
}
}
}
}
]
});
}
handler(req, res, next) {
res.json({ data: 'this is a op1' });
}
}
class MyOperation2 extends arrest.Operation {
constructor(resource, path, method) {
super('op2', resource, path, method);
this.setInfo({
parameters: [
{
name: 'lang',
in: 'query',
type: 'string',
required: true
},
{
name: 'count',
in: 'query',
type: 'integer'
}
]
});
}
handler(req, res, next) {
res.json({ data: 'this is a op2' });
}
}
class MyResource extends arrest.Resource {
constructor() {
super();
this.addOperation(new MyOperation1(this, '/', 'post'));
this.addOperation(new MyOperation2(this, '/', 'get'));
}
}
Omitting the body or passing an invalid body (e.g. an object without the name property) when POST
ing to
http://localhost/my-resources
will return an error. Likewise GET
ting without a lang parameter or with a count
set to anything other than a number will fail.
Scopes and security validators
TBA
Creating an API with a MongoDB data store
TBA (default api routes)
Using arrest with express
TBA
Debugging
TBA
API documentation
TBA
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
2 years ago
2 years ago
3 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago