npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

arrest

v13.2.5

Published

OpenAPI v3 compliant REST framework for Node.js, with support for MongoDB and JSON-Schema

Downloads

1,835

Readme

arrest

Swagger REST framework for Node.js, with support for MongoDB and JSON-Schema

travis build Coverage Status npm version

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 on http://localhost/some-resources
  • POST on http://localhost/some-resources
  • PUT on http://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 GETs 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 POSTing to http://localhost/my-resources will return an error. Likewise GETting 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