RESTAPiService microlibrary brings a quick and flexible solution to initiate a generic RESTful API server application with NodeJs.
- ✅ Flexible & Configurable
- ✅ Tiny & light : about 30 kB
- ✅ Private Endpoints supported (token authentication)
- ✅ Support for secure connections ( https )
- ✅ Minimum boilerplate to initialize
- ✅ Simple routes declaration syntax
- ✅ ES6 & CommonJS module import syntax supported (import & require)
- ✅ Typescript support
Usage example :
// import the library and some controllers
import RESTApiService from 'rest-api-service'
import Controllers from './controllers'
// declare api routes
const myRoutes = [
['GET', 'user/:id/profile', Controllers.user.getSomething, false],
['POST', 'user/:id/email', Controllers.user.setSomething, true]
// ...
]
// initialize service
const myService = await RESTApiService.create(myRoutes, {
protocol: 'http',
port: 8080,
verbose: true
})
// done!
The Controllers :
export default {
user: {
getSomething(response, payload, token) {
// retrieve "something" , and return it...
const something = my_db_select_something(payload.body.something.id)
if (something) response(200, { something })
else response(404)
},
setSomething(response, payload, token) {
// save "something" and respond with status 200
my_db_insert_something(payload.body.something)
response(200)
}
}
}
This package can be installed locally with both yarn
and npm
:
# using yarn...
$ yarn add rest-api-service
# or with npm...
$ npm install rest-api-service
Once installed, you are ready tom import it to your project.
// import using ES& syntax
import RESTApiService from 'rest-api-service'
// or using COMMONJS syntax
const RESTApiService = require('rest-api-service').default
The asynchronous constructor initiates the service and returns an instance of the RESTApiService.
async RESTApiService.create( routes:RESTApiServiceRoute[] [, options:RESTApiServiceOptions] )
routes
: Array containing a collection of routes.options
(optional) : Object containing the configuration options.
The RESTApiService constructor expects you to provide a Collection (array) of routes. Each route is itself an Array too, and is expected to have the following structure (indexes values) :
[HTTPMethod, URIPattern, RouteController, PrivateRouteFlag]
HTTPMethod
(string) : Available methods :GET | POST | PUT | PATCH | DELETE
URIPattern
(string) : Define the endpoints at which requests can be made. Route paths must be string patterns, containing -if needed- route parameters, to capture values (more info here)RouteController
(function) : Method to handle the calls to the different endpoints.PrivateRouteFlag
(boolean, optional) : Boolean value to flag those endpoints that are private and require authentication.
The RESTApiService constructor accepts the following configuration options :
{
port: number // default : 8080
protocol: 'http' | 'https' // default : http
verbose: boolean // default : false
logErrors: boolean // default : false
cors: Object // default : {}
auth: Function // default : ()=>true
credentials: {
cert: string // content of a .crt file
key: string // content of a .key file
}
}
port
: Number of port to listenprotocol
: Protocol to useverbose
: When set to true, activity will be output to consolelogErrors
: When set to true, Controller errors will be printed in the consolecors
: Object to set the CORS configuration (use this syntax)auth
: Authorizer (sync or sync) function to block/allow access to a private endpoint. Receives a token as single argument, and must return a booleancredentials
: Object containing the secret key and the certificate for secure connections (only required when using https protocol)
const myController = (response, { body, params, query }, token) => {
// ...do some stuff
response(200, { success: true })
}
Controller methods are functions (sync or async) that handle the calls to an endpoint. They are not meant to return any value, instead they can execute the provided response
method to deliver the result of their operations to the client.
-
If the controller method finishes its execution without executing the
response
method, aresponse(200)
will be executed automatically. -
Any unhandled error triggered during a Controller execution will be catch and a
response(500)
(Server internal error) will be emitted as a response to the client.
Controller errors will not be output to the console unless the
logErrors
option has been set to true during initialization stage.
All Route controllers will be invoked providing to them the following parameters :
-
Response method : Is a function provided as first argument to the Controller. It can be used to emit a response to the client, it accepts 2 parameters :
- Status Code : Number representing the HTTP status code
- Data (optional) : JSON object containing the data to return
-
Payload : Provided as the second argument, is an object that acts as a container for all the incoming -client provided- data, which is grouped , according to its source, in the following properties :
body
(JSON) : Body of the request (for requests like POST or PUT)params
(JSON) : Any URL parameter from the route (eg : user/:id )query
(JSON) : Any url query parameter (eg : ?foo=bar)
-
Token : In the third argument the Route Controller receives the auth token extracted from the request header (auth-token header). Is specially useful to identify the requester.
Those routes that are declared with the PrivateRouteFlag
set to true
will trigger the execution of the Authorizer (provided during initialization stage with the auth
property)
The Route Authorizer
(sync or async) function receives the request auth token (extracted from the auth-token
request header) , and must return a boolean
indicating if the request can proceed or must be blocked.
Rejected requests will be finished with a 401
status code.
A pseudo-code implementation of an Authorizer could be the following:
function requestAuthorizer(token) {
// ...perform token validation
const result = myTokenValidationRoutine(token)
// allow or block according the validation
return result ? true : false
}
CORS can be configured during initialization stage using the cors
option.
An example of a permissive configuration, which allows request from any source would be :
"cors": {
"credentials": true,
"origin": "*"
}
More information about setting up CORS , and available CORS configuration can be found here : https://expressjs.com/en/resources/middleware/cors.html
The destroy
method will terminate and shutdown gracefully the server and all its connections.
const myService = await RESTApiService.create(myRoutes)
await myService.destroy()
RESTApiService ha been implemented using Typescript. Types signatures can be easily imported using :
import {
RESTApiServiceOptions, // type for constructor options
RESTApiServiceRoute, // type for route definition
RESTApiServiceRequestAuthorizer, // type for request authorizer
RESTApiServiceController, // type for route controller
API_AUTH_REQUIRED // constant for route private flags
} from 'rest-api-service'
*Additional types are also available for import
Available scripts :
yarn start
: starts the serviceyarn lint
: run the linteryarn test
: run the testsyarn build
: compiles to javascript the libraryyarn publish
: compiles to javascript the library and publishes to npm registry
This library is released using a MIT license