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

resting-squirrel

v2.28.2

Published

Simple REST server with json input data.

Downloads

856

Readme

Resting Squirrel

Simple REST server with json input data. It uses express functions for register endpoints. Non-existing routes are automatically handled and return 404 status.

Installation

$ npm install resting-squirrel

Usage

import rs, { Param, Type, Field, ErrorField, RouteAuth } from 'resting-squirrel';

const app = rs();

// Simple definition
// Simple endpoint
app.get("/", (req, res, next) => next(null, { success: true }));
// Endpoint which requires authorization with specified version
app.get(0, '/user', true, (req, res, next) => next(null, { success: true}));
// Endpoint which requires authorization with incremented version causing 0 version endpoint is deprecated 
app.get(1, '/user', true, (req, res, next) => next(null, { success: true}));
// Endpoint with defined required parameter
app.put(0, '/user', false, [new Param('name', true, Type.string, 'Name of the user')], (req, res, next) => next(null, { success: true }));
// Endpoint with description
app.get('/documented', false, [], 'I am documented endpoint.', (req, res, next) => next(null, { success: true }));

// Complex definition
app.post(0, '/user/:id', {
    // Endpoint requires authorization
    auth: RouteAuth.REQUIRED,
    // Route argument "id" must be an integer
    args: [
        new Field('id', Type.integer, 'Identifier of the user to update'),
    ],
    // Endpoint accepts parameter name which has to be a string
    params: [
        new Param('name', false, Type.string, 'Name of the user'),
    ],
    // Endpoints returns object with parameters id (casted to integer before rendering data) and name
    response: [
        new Field('id', Type.integer, 'Identifier of the user'),
        new Field('name', Type.string, 'Name of the user'),
    ],
    // Description for the documentation
    description: 'Updates the user information',
    errors: [
        new ErrorField('ERR_INVALID_USER', 'Returned if request id of the user does not exist.'),
    ],
}, (req, res, next) => User.update(req.params.id, req.body, next));

app.start();

This usage will create the app with default options.

Options

port Port where the app listens. Default: 8080
name Name of the app. Default: Resting Squirrel App
dataKey Key in the output where the data are sent. Default: data
errorKey Key in the output where the error is sent. Default: error
requestLimit Limit for input data. Default: 1mb
charset Charset of the response. Default: utf-8
meta Object for setting up the behavior of meta data.

  • enabled If true meta data are showed in every request. Default: true
  • data Custom meta data for the application. This data are set for all endpoints. Default: {}

log Object to configure logging options.

  • enabled If true the logging is enabled. Default: true
  • level Logging level (error, warning, verbose). Default: verbose
  • stack If true the error stack is logged if logging is enabled. Default: true
    logStack If true and log is enabled the stack trace is written in stdout. This option should be false on the production app -> the request process is longer if the complete stack is printed to the console. Default: true DEPRECATED
    logger({ statusCode, method, path, spec, body, params, query, headers, took, response }) Custom logging function which is called before the request ends. Default function logs the data in the console like in previous versions.

docs Object for setting up the documentation for the API.

  • enabled If true docs are enabled on the options.docs.endpoint endpoint. Default: true
  • endpoint On this endpoint is shown documentation. Default: /docs
  • auth If true documentation request must be authorized with options.auth function. Default: false DEPRECATED Using api key is preferred option.
  • paramsAsArray If true params are returned as array in the docs. Default: false

auth Object for setting up the authorization.

  • key Key in the headers where the access token is. Default: x-token
  • description Custom description of the authorization process. Default: null
  • validator(key, req, res, next) Function which validates the access token. Default function just checks if the header with key exists.

apiKey Object for setting up the api key.

  • enabled If true api key is validated. Default: false
  • type Type of the location of api key in request. One of qs, body, header. Default: qs
  • validator(apiKey, next) Validator of api key. It should return Promise<boolean>.

timeout Time in milliseconds. After this time the endpoints return 408 status code. Default: null
before Object of functions with key as a route spec. The functions (req, res, next) are called before the endpoint execution. Default object on all endpoints just calls next(). DEPRECATED
after(isError, data, req, res, next) Object of functions with key as a route spec. The functions (err, data, req, res, next) are called after the endpoint execution. Default object on all endpoints just calls next(). DEPRECATED
defaultError Default error for response if no error is defined

  • statusCode Default HTTP status code on error. Default: 500
  • message Default error message. Default: Server error
  • code Default error code. Default: unknown

validateParams If true the params are validated and the validator message is printed in stdout as warning if something is found. Default: true
responseStrictValidation If true the Error is thrown if response key has invalid type. Default: false

Errors

Module is using SmartError as base error and HttpSmartError for http errors.

import { Error, HttpError } from 'resting-squirrel';

console.log(new Error("Some error", "some_code")); // Error with message "Some error" and code "ERR_SOME_CODE"
console.log(HttpError.create(400)); // Http error with 400 status code, message "Bad request" and code "ERR_BAD_REQUEST"

Functions DEPRECATED

use(route, callback) Registers express middleware. Route can be callback.
get(version, route, requiredAuth = false, params = [], docs = null, callback) Registers route on the GET method. requiredAuth, params and docs can be callback. Callback is taken from express.
post(version, route, requiredAuth = false, params = [], docs = null, callback) Registers route on the POST method. requiredAuth, params and docs can be callback. Callback is taken from express.
put(version, route, requiredAuth = false, params = [], docs = null, callback) Registers route on the PUT method. requiredAuth, params and docs can be callback. Callback is taken from express.
delete(version, route, requiredAuth = false, params = [], docs = null, callback) Registers route on the DELETE method. requiredAuth, params and docs can be callback. Callback is taken from express.
head(version, route, requiredAuth = false, params = [], docs = null, callback) Registers route on the HEAD method. requiredAuth, params and docs can be callback. Callback is taken from express.
listen(cb) Starts listening on the port from options. DEPRECATED
start(cb) Starts listening on the port from options.

Functions

use(route, callback) Registers express middleware. Route can be callback.
registerApiKeyHandler(handler) Registers handler (apiKey, req) to validate api key. registerBeforeExecution(spec, callback) Registers callback (req, res) to the route spec which is executed before the endpoint execution.
registerAfterExecution(spec, callback) Registers callback (isError, data, req, res) to the route spec which is executed after the endpoint execution.
get(version, route, options = {}, callback) Registers route on the GET method. options can be callback. Callback is taken from express.
post(version, route, options = {}, callback) Registers route on the POST method. options can be callback. Callback is taken from express.
put(version, route, options = {}, callback) Registers route on the PUT method. options can be callback. Callback is taken from express.
delete(version, route, options = {}, callback) Registers route on the DELETE method. options can be callback. Callback is taken from express.
head(version, route, options = {}, callback) Registers route on the HEAD method. options can be callback. Callback is taken from express.
listen(cb) Starts listening on the port from options. DEPRECATED
start(cb) Starts listening on the port from options.

Data handling

All http methods are using the same function for handling data. First parameter in the callback is error and second are data which are sent to the options.dataKey in the response.

app.get(0, '/user', (req, res, next) => {
    const { user } = req;
    next(null, user);
});
Promises

The callback function can return promise or be an async function. Entire callback function is surrounded with try-catch block so all rejects in async functions are handled as errors.

app.get(0, '/user', (req, res, next) => {
    const { user } = req;
    return new Promise(resolve => resolve(user));
});
app.get(1, '/user', async (req) => {
    const { user } = req;
    await user.doSomeAsyncStuff();
    return user;
});

For 204 response code just return null in the promise.

Endpoint options

auth Indicates auth process of the endpoint.
requireAuth If true the endpoint requires authorization. DEPRECATED
description Description of the endpoint.
args List of Field instances to define endpoint arguments. If it's not defined all arguments defined in the route are of any type.
params List of Param instances to define endpoint parameters.
response List of Field instances to define endpoint response fields.
errors List of ErrorField instances to define errors which could be returned during the execution.
hideDocs If true the endpoint is hidden from the documentation.
requireApiKey If false the endpoint doesn't require an api key in the request. This option overrides the options.apiKey.enabled option if it's false. It's not recommended to use this option.
props Custom props for the endpoint.
redirect Indicates if the endpoint is redirecting after the execution. The callback must return string where the request is redirected.

Arguments

The list of arguments fields in the http methods is array of Field instances. The values are validated with type checking.

import rs, { Param, Field, Type } from 'resting-squirrel';

const app = rs();

// It creates integer argument field with name int_arg
const f1 = new Field('int_arg', Type.integer, 'Integer argument');

// It creates float response field with name float_arg
const f2 = Field.create({
    name: 'float_arg',
    type: Type.float,
    description: 'Float argument',
});

// It creates any argument field with name any_arg
const f3 = Field.create('any_arg');

// Registers the GET endpoint which validates the arguments.
app.get(0, '/fields', {
    args: [f1, f2, f3],
    description: 'Test endpoint for argument examples',
}, (req, res, next) => next(null, req.params));

Params

The list of params in the http methods can be array of strings or array of Param instances. The params are input json in the POST, PUT, DELETE methods or query string in the GET method.

String array

The string array of the parameters is deprecated. It creates Param instances from string. The parameter has the name from the string, it will be required, the type will be any and it won't have a description.

Param array

The Param class can by required from the module.

import rs, { Param, Type } from 'resting-squirrel';

const app = rs();

// It creates required integer parameter with name int_param
const p1 = new Param('int_param', true, Type.integer, 'Integer parameter');

// It creates required float parameter with name float_param
const p2 = Param.create({
    name: 'float_param', 
    required: true,
    type: Type.float,
    description: 'Float parameter',
});

// It creates required any parameter with name any_param
const p3 = Param.create('any_param');

// Registers the GET endpoint which requires three parameters to execute
app.get(0, '/params', false, [p1, p2, p3], 'Test endpoint for param examples', (req, res, next) => next(null, req.query));

The Param class uses type definition from the runtime-type for type checking.

Response definition

The list of response fields in the http methods is array of Field instances. Response data sent to next function in endpoint callback are validated with type checking to render correct data-types.

import rs, { Param, Field, Type, Response } from 'resting-squirrel';

const app = rs();

// It creates integer response field with name int_field
const f1 = new Field('int_field', Type.integer, 'Integer response field');

// It creates float response field with name float_field
const f2 = Field.create({
    name: 'float_field',
    type: Type.float,
    description: 'Float response field',
});

// It creates any response field with name any_field
const f3 = Field.create('any_field');

const doSomeStuff = () => {
    return {
        int_field: 666,
        float_field: 6.66,
        any_field: 'satan',
    };
};

// Registers the GET endpoint which validates the fields before the data render.
app.get(0, '/fields', {
    response: [f1, f2, f3],
    description: 'Test endpoint for field examples',
}, (req, res, next) => next(null, doSomeStuff()));

// Equivalent of the previous register but using a JSON Response instance.
app.get(1, '/fields', {
    response: new Response.JSON([f1, f2, f3]),
    description: 'Test endpoint for field examples',
}, (req, res, next) => next(null, doSomeStuff()));

// Registers the GET endpoint which sends a image content.
app.get(0, '/fields', {
    response: new Custom.Response('image/png'),
}, (req, res, next) => next(null, '[SOME IMAGE DATA]'));

Shapes

In some cases is needed to use shape field (param). Shapes are JS objects. The field (param) can have Type.shape but it's not effective for the documentation. For this purpose Field (Param) class has static classes Shape and ShapeArray.

Field.Shape
constructor

| field | type | description | | ------------- |:-------------:| --------------------------- | | name | string | Name of the field | | description | string | Description of the field | | ...fields | Field[] | List of fields in the shape |

Field.ShapeArray
constructor

| field | type | description | | ------------- |:-------------:| --------------------------- | | name | string | Name of the field | | description | string | Description of the field | | ...fields | Field[] | List of fields in the shape |

Param.Shape
constructor

| field | type | description | | ------------- |:-------------:| ---------------------------------- | | name | string | Name of the param | | required | boolean | Indicates if the param is required | | description | string | Description of the param | | ...params | Param[] | List of params in the shape |

Param.ShapeArray
constructor

| field | type | description | | ------------- |:-------------:| ---------------------------------- | | name | string | Name of the param | | required | boolean | Indicates if the param is required | | description | string | Description of the param | | ...params | Param[] | List of params in the shape |

Response methods in the callback

send204() Sets 204 http code and sends empty response.
send401(message = "Unauthorized request", code = "unauthorized_request") Sets 401 http code and sends the Error instance.
send404(message = "Page not found", code = "page_not_found") Sets 404 http code and sends the Error instance.
send501(message = "Not implemented", code = "not_implemented") Sets 501 http code and sends Error instance.
addMeta(key, value) Adds custom meta key and value for current request.
sendData(data) Sends the data to the options.dataKey in response. DEPRECATED: You should use the callback in http methods
sendError(code = options.defaultError.statusCode, message = options.defaultError.message, errorCode = options.defaultError.code) Sets the code as http code and sends the Error instance.

Reserved GET parameters

This parameters are updating behavior of the current request.
nometa If meta is enabled in config this parameter will disable it.
pretty JSON response is printed for human reading.

Time out

If timeout option (global or endpoint) is set the execution process is killed in the first possible moment (some lifecycle methods are still called). If the timeout occurred during the endpoint callback execution the execution is still in process but the event timeout is called to the express.Request.on method.

app.get(0, '/timeout', { timeout: 500 }, (req, res, next) => {
    const timeout = setTimeout(() => {
        // some stuff
        next();
    }, 1000);
    req.on('timeout', () => clearTimeout(timeout));
});

The above example will clear the timeout after the 500ms and 408 error is returned.

Documentation

The module creates generic documentation by default. The documentation is on the /docs route (if it's not set in app options) as a JSON data. /docs.html contains simple HTML which converts the JSON data to HTML and adds the test console.

Recommendations

  • Do not use Type.shape in args, params and fields definition. It'll be documented as shape string from the runtime-type module.
  • Do not use Type.any in args, params and fields definition. Any type is not validated as a type so it can be anything.
  • Use HttpError for errors sent to the endpoint callback.

Support modules

resting-squirrel-dto

Module to define DTOs to simply define documentation.

resting-squirrel-controller

Module to use class controllers to define endpoints.

Thanks