rest-express-wrapper v0.3.7
QuickExpress (rest-express-wrapper)
QuickExpress is an express wrapper created to initialise REST endpoints and validate all calls globally.
To utilise the rate limiting function, a mongo database object must provided. Support for alternatives will be added in due course (Redis, Memcache, mySQL & PostGres)
Setup
Creating endpoints
Without rate limiter
const endpoint: EndpointStruc = {
name: 'TestEndpoint',
path: 'testendpoint',
defaultPath: 'path',
type: 'GET',
headers: ['text'],
execute(
req: express.Request,
res: express.Response,
headers: express.Headers
) {
res.status(200).send(headers.text);
},
};
With limiter:
const endpoint: EndpointStruc = {
name: 'TestEndpoint',
path: 'testendpoint',
defaultPath: 'path',
type: 'GET',
headers: ['text'],
limiter: {
points: 10,
duration: '1d', /* other examples: 500 (500 seconds), '1m' (60 seconds), '5m' (300 seconds), '10h' (36000 seconds), '1d' (86400 seconds) */
keyPrefix: 'testlimiter' /* Name of table in database */
}
execute(
req: express.Request,
res: express.Response,
headers: express.Headers
) {
res.status(200).send(headers.text);
},
};
Creating the express wrapper object
Without rate limiter:
const app = express();
const expressWrapper = new ExpressWrapper({
endpoints,
expressApp: app,
});
With rate limiter:
const { MongoClient } = require('mongodb');
const mongoOpts = {
useNewUrlParser: true,
};
const mongoConn = MongoClient.connect('mongodb://localhost:27017', mongoOpts);
const app = express();
const expressWrapper = new ExpressWrapper({
endpoints,
expressApp: app,
limiter: { mongoClient: mongoConn.db('rate_limiter_database_name') },
});
Initialise endpoints
Before endpoints can be reached, you must initialise them via:
expressWrapper.initialise();
Using custom validation
Validation request
You can pass a custom validation function that is applied when any endpoint is reached, this could include validating user logins/sessions or confirming the contents of specific headers.
The custom validation function accepts the following arguments as an object (typescript interface: 'ValidationRequest'):
{
headers: express.Headers;
body?: express.body;
endpoint: EndpointStruc
}
And must return an object containing a boolean success key. Full response options:
{
success: boolean;
status?: number;
error?: string;
headers?: any;
}
Example of validation function utilising all possible return options.
Standard response:
const customValidator = ({
headers,
body,
endpoint,
}: ValidationRequest): Promise<ValidationResponse> => {
if (headers.clientid === process.env.CLIENT_ID) {
return { success: true, headers: { userID: resp.userid } };
} else {
return {
success: false,
status: 401,
error: 'Invalid client id provided, unauthorised',
};
}
};
As a promise:
const customValidator = ({
headers,
body,
endpointName,
endpointType,
}: ValidationRequest): Promise<ValidationResponse> =>
new Promise((resolve) => {
// Here checkLogin is a promise function used to validate an active session key
checkLogin(headers.sessionkey).then((resp) => {
if (resp.success) {
resolve({ success: true, headers: { userID: resp.userid } });
} else {
resolve({
success: false,
status: 401,
error: 'Invalid session key provided, unauthorised',
});
}
});
});
Limiter identifier
The identifier used in determining a request origin can be customised. By default, req.ip is used from the express request object but this is not always sufficient.
To pass a custom identifier, you can define a function similar to below:
const getLimiterIdentifier = (req: express.Request): string => {
return req.headers['x-forwarded-for'] || req.socket.remoteAddress;
};
Constructor
To initialise the wrapper, the following must be passed
Object Key | Description | Required |
---|---|---|
endpoints | Array of endpoints (see structure below) | x |
limiter | Object containing limiter database and any options | |
expressApp | Express Application (new Express()) | x |
additionalLimiterOptions | Additional limiter options (see options) | |
validateRequest | Custom function used for request validation | |
getLimiterIdentifier | Custom function used to set identifier used for limiter |
Constructor limiter object
Object Key | Description | Required |
---|---|---|
mongoClient | Mongo database db object | |
limiterOptions | rate limiter options relevant to the type of database passed |
Endpoint structure
Endpoints contain the following
Object Key | Description | Example data | Required |
---|---|---|---|
name | Name of endpoint | login | x |
disabled | Disable the endpoint (not callable) | true | |
path | REST path | login | x |
defaultPath | REST path prefix | auth | x |
limiter | Limiter object | true | |
type | Request type | GET | x |
headers | Required headers | 'clientid' | |
body | Require body (requires body in JSON format)* | 'id', 'name' | |
execute | Function executed on endpoint reached | execute(req,res,headers){} | x |
*Body requires either express.json() or bodyParser() middleware in order to access the JSON req.body (e.g. app.use(express.json()))
Limiter object
Note: In order to utilise the rate limiter, a valid database object must be passed to the constructor
Object Key | Description | Example data | Required |
---|---|---|---|
points | Hits allowed before limit enforced | 5 | x |
duration | Time before points are reset | '2h' | x |
keyPrefix | key used to identifer limiter in database | 'loginrx' |