express-requestprocessor
v0.0.0-beta23
Published
NPM Module that automatically loads Services from a specific and serves them using express.
Downloads
5
Maintainers
Readme
RequestProcessor for express
RequestProcessor is used to build all routes from a folder for an api using express.
If you have any trouble with the RequestProcessor, just try the demo or open an issue!
Controlling the Request Processor
Before starting the RequestProcessor, you need to configure it. After that you can start/stop/or restart it using just a single command.
const RequestProcessor = require('express-requestprocessor');
const Config = {
log: {
level: RequestProcessor.Logger.levels.DEBUG,
output: (out, message) => console.log(message),
},
serviceFolder: '/services',
port: 5000,
authorize: authorizeUsingBasicAuth,
requestSize: '1mb',
notFoundPage: (req, res) => {
return 'Sorry this page was not found!';
},
docs: {
route: '/docs',
title: 'Request Processor Demo Services',
description: 'For demonstration purpose!',
version: '1.0.0',
host: 'localhost:8080',
basePath: '',
additionalDocsPath: ["src/types/**/*.ts"],
produces: ['application/json'],
securityDefinitions: {
basic: {
type: 'basic',
},
},
},
};
RequestProcessor
.configure(Config)
.start();
Configuration Items
- log.level optional
ENUM
: Level of Logging, Possible Values:RequestProcessor.Logger.levels.
[TRACE
,DEBUG
,INFO
,WARNING
,ERROR
]. If not set every message will be logged (similar to levelTRACE
). - log.output required
function
: Output function for log messages (you can do whatever you want with the long entries). This output includes an object with raw details (level
,message
,source
,details
) and a parsed message containing all elements of the object. - serviceFolder required
String
: Folder path, starting from your project root, where services are located (subfolders are also allowed). - apiBasePath: optional
String
: If the api should run in a subfolder (e.g./api
), you need to specify it here. - port required
Number
: Port where the api will be available. - authorize optional
Function
: Authorizer function that will be called for every request to handle the authorization. - requestSize optional
String
: Maximum size of a request (if it's larger status413
will be returned). Sample values:1b
,10kb
20mb
,30gb
,40tb
,50pb
, for more information visit bytes.js readme - notFoundPage optional
Handler Object
: Handles all requests, that does not fit to any provided service. You just need to provide a Handler Object in the config. - docs optional
boolean
/object
: Enables Swagger docs. Visit Doc definition chapter for more information. - docs.route optional
string
: Path to swagger docs, by default{apiBaseUrl}/docs
. - docs.title optional
string
: Title of your api. - docs.description optional
string
: Description of your api. - docs.version optional
string
: Api Version. - docs.host optional
string
: Host name of your api. - docs.basePath optional
string
: Path to your api (e.g. if it is in a subdirectory), by default apiBasePath is used, but you can override it with this value. - docs.additionalDocsPath optional
string[]
: Additional path for your swagger docs. If you want to add docs from another folder than theserviceFolder
than you have to add it here. - docs.schemes optional
string[]
: You can specify schemes likehttp
orhttps
here, default['http', 'https']
. - docs.produces optional
string[]
: Produces header, if you want to provide anything else or more than JSON, e.g.application/json
,application/xml
. - docs.securityDefinitions optional
string
: Adds support for Authentication. For basic auth you need to insert{basic: {type: basic}}
, if you want to support other authentication techniques refer to the documentation
Defining Services
For defining services you need to call RequestProcessor.process(...)
inside your service, that is located in your services folder.
You can call the process
function with following parameters:
RequestProcessor.process({
path: "/test", // this is the endpoint path
get: handleGet, // handler functions can be configured the simple way without additional information
role: "testrole", //todo
post: {
handle: handlePost, // or inside a special object
validate: validatePost, // e.g. if you want to use the validator that is
role: "testpostrole", // todo
link: { // link header configuration (can be an array or an object)
name: 'Dispatcher', // name of the service that should be linked
url: '/', // service path
}
},
put: handlePut,
delete: handleDelete,
validate: validate, // this validator gets only be called when using the GET method
link: [ // link header configuration (can be a array or an object)
{
name: 'Test 1', // name of the service that should be linked
url: '/test/1', // service path
},
{
name: 'Test 2',
url: '/test/2',
}
]
});
It is possible to set configration inside and outside the request method configuration (GET
, POST
, PUT
, DELETE
).
If you set it outside, it will be used if there is nothing defined inside.
You can provide a Handler and a Validator function for each method. The validator function should validate inputs, a hander should process the request and return a result.
Validator
You can put validator functions (that should be named validate or validateMethod e.g. validateGet) inside the config object or inside get/post/put/delete. If its inside the function will only be called if this method is used. If it is outside it will be called for all methods that do not have an own validate function inside.
A validator should return true or nothing if the validation was successful otherwise it should return false or throw an exception.
The handler method gets only a request object.
Request object (mostly called req):
let req = {
"method": "GET",
"query": {
"name1": "value1",
"name2": "value2"
},
"path": "/test/where/am/i",
"headers": {
"name1": "value1",
"name2": "value2"
},
"body": {
"about": "this object can also be an array, a string, a number or anything else"
},
"auth": "Return value of an Authorizer if provided (can be used for user data)",
"role": "role provided in RequestProcessor.process('this will be provided')",
"endpoint": "/service/:id"
}
Handler
You can add a handler to one of get/post/put/delete variables or an object that contains a variable called handler with a handler function inside. That is useful if you want to use the validator function.
The handler method gets a request and a response object.
Request object (mostly called req):
let req = {
"method": "GET",
"query": {
"name1": "value1",
"name2": "value2"
},
"path": "/test/where/am/i",
"headers": {
"name1": "value1",
"name2": "value2"
},
"body": {
"about": "this object can also be an array, a string, a number or anything else"
},
"auth": "Return value of an Authorizer if provided (can be used for user data)",
"role": "role provided in RequestProcessor.process('this will be provided"
}
Response object (mostly called res):
let res = {
"status": 200, // status code
"body": { // any bode that should be returned
"about": "this object can also be an array, a string, a number or anything else"
},
"header": { // provide any header you want
"name1": "value1",
"name2": "value2"
},
cookie: { // provide any cookies you want
"name": { // cookie name
value: "anyCookieValue", // value of this cookie
maxAge: 36000000, // max age in ms (36000000ms = 1h)
domain: "minis-lioba.de" // domain for this cookie (only subdomains on the same domain are allowed)
}
},
"file": "test.png" // You can any file that will be returned, but if you provide a value the file will be sent to the user instead of a body.
}
Authorizer
Providing an authorization function is only optional.
This function will be called every time an endpoint is called. It should be used to verify using headers, roles or something else wheater a user is allowed to access this endpoint or not. If so, an object could be returned that will be forwarded to the Validator and Handler. If not, an exception should can be thrown and the user gets an error message (Validator and Handler won't be called).
A authorize function can look like that:
const allowedUsers = [
{
name: 'user',
password: 'pass',
},
{
name: 'test',
password: 'test',
},
];
const authorizeBasicAuth = function(req) {
const trowable = {status: 401, message: 'Authorization failed'};
if (!req.headers.authorization) throw trowable;
let authHeader = req.headers.authorization;
if (!authHeader.startsWith('Basic ')) throw trowable;
authHeader = authHeader.replace('Basic ', '');
const login = Buffer.from(authHeader, 'base64').toString().split(':');
for (let i=0; i<allowedUsers.length; ++i) {
if (allowedUsers[i].name === login[0]
&& allowedUsers[i].password === login[1]) return {user: login[0]};
}
throw trowable;
};
Automatic Status Codes
The RequestProcessor will automatically return following status codes:
- 200: If everything was ok and nothing special happened
- 201: If everything was ok for POST method
- 204: If the response body is empty, but the request was processed successfully
- 400: If the validator function throws an error or returns false
- 500: If the handle function throws an error
You can always override this automatic status codes by changing the res.status
variable in the handle function (res.status=200
) or by throwing an error with a status
value inside the error object (throw {status: 500, message: "Just an error"}
)
Typescript Support
This software supports Typescript. You can use it in the common way.
Useful types:
ReqType
for variablereq
inside the handler and validator.ResType
for variableres
inside the handler and validator.
Docs
First you need to enable docs in the config.
After that you can create a doc definition just inside the service. Therefor you have to create a jsdoc with following keywords:
- just inside the jsdoc: Description of the service
@group
Create a group with multiple services/http method@route
: Define http method and path like@route GET /sum
, you can also define path params@route GET /sum/{a}/{b}
.@param
: Defines a request param, Syntax:@param {type} name.paramType.required Description
: if you provide.required
than the user is force to fill this param.- Query Params: e.g.
@param {Integer} a.query Param a
,@param {Object} b.query.required Param b
- Path Params: e.g.
@param {Integer} a.path.required Variable a
- Query Params: e.g.
@return
: Adds return status code an description e.g.@return {type} 200 - Description
For more information try the demo api or have a look at this documentation
Demo API
To see how the RequestProcessor is working, it is better to look at the demo files:
git clone [email protected]:FelixFranz/express-requestprocessor.git
npm install
npm start
Open the Address displayed in the console
- Look at
test/services
for the service implementation