@libstack/router
v1.0.0
Published
An extreme powerful Express Routing machine
Downloads
2
Maintainers
Readme
@libstack/router
An extreme powerful Express Routing machine
What is it ?
This module adds the async/await to your express app. In addition to promise, you can add endpoint configurations so you can intercept the request and do everything you want.
Installation
npm install @libstack/router --save
Usage
You can create routes and interceptors. Let's first take a look on how to create routers.
Routers
Routers are entrypoints on your application, you can define one with multiple endpoints, which have the default start path from the router.
import { RestController, GET, POST, BadRequestError } from '@libstack/router';
// Supported methods: GET, POST, PUT, DELETE
@RestController('/myController')
class TestRouter {
// The second argument is used for Interceptors (will be described in the next section)
@GET('/', { addProperty: true })
async get() {
const result = await someModule.execAsyncCall();
return result;
}
@GET('/customEnd')
async customEnd(req:Request, res:Response) {
res.end('my custom end');
// you can define the response you want by just calling res.end (from the express)
}
@POST('/throwError')
async throwError() {
throw new BadRequestError('My error message');
// this error, when thrown, will return a 400 status code with this structure
// { "message": "My error message" }
}
}
Interceptors
So, what is exactly an interceptor? Interceptors are business logics that needs to be executed on specific endpoints or all endpoits, it's up to you. Examples of interceptors are:
- Error Interceptor: Interceptor to catch one specific Error and return data to the API
- Validation Interceptor: Catch body and check if the request is valid
- Authentication Interceptor: Used to allow only authenticated users
- ACL Interceptor: Used to allow only authenticated users that have roles to perform a request
Alright, so how can we create interceptors? So, let's give an example of interceptor that adds a property to the response body (just an example).
import { Request, Response } from 'express';
import { UnauthorizedError, CallableStack, Interceptor, RestInterceptor } from '@libstack/router';
import { getUserData, User } from './MyUserService';
@RestInterceptor
class ChangeResponseInterceptor implements Interceptor {
/**
* This method will be called on every request and the parameters are defined
* on the second argument on @GET @POST @PUT and @DELETE decorators
*/
intercepts(parameters: any): boolean {
// so, for example, we created an interceptor that intercepts ALL requests
return true;
}
/**
* This method will only be executed if the condition on `intercepts` is true
*/
async execute(parameters: any, req: Request, res: Response, stack: CallableStack): Promise<any> {
/*
* What exactly is this stack?
* This is the interceptor execution stack. All interceptors
* are linked within the Callable Stack and in order to continue
* the execution you need to call next(). If you don't call next() it will
* halt the request stack.
*/
const response: any = await stack.next();
// here we are changing the response
if (response) {
response.hello = 'Hello World';
}
return response; // if you don't return, there will be no response
}
}
Errors
There are some predefined errors on the module
BadRequestError
: Will return400
NotFoundError
: Will return404
UnauthorizedError
: Will return401
ForbiddenError
: Will return403
But you can also create your own HTTP error by just extending HttpError
import { HttpError } from '@libstack/router';
export class UnauthorizedError extends HttpError {
constructor(message: string, data?: any) {
super(message, 401, data);
}
}
As you can see, there's a data
property on HttpErrors, they are used to send additional information about the error, for example, validation error must return which fields weren't properly set.
Linking @libstack/router on your express application
So, let's pretend we have created a router on ./routers/MyRouter.ts
and an interceptor on ./interceptors/MyInterceptor.ts
import express from 'express';
import controller from '@libstack/router';
// then you will need to import the routers and interceptors in order to be loaded
// just import the router and interceptors and they'll be attached to the `controller`
import './routers/MyRouter';
import './interceptors/MyInterceptor';
const app = express();
app.use(controller.router); // use plugin the @libstack/router to your express app
app.listen(process.env.PORT || 8080);