Controllers
Developers coming from MVC will know what is a controller and how it helps us to handle the request and response lifecycle.
RestController Introduction
For elegant handling we have added a base RestController
which has all the necessary functions to handle the response transformation. While creating your controller, remember to extend RestController
.
Check below to know how to create a controller.
import { RestController, Request, Response } from '@app/core';
import { Controller, Get, Req, Res } from '@nestjs/common';
import { UserService } from '../services';
import { UserDetailTransformer } from '@app/transformer';
@Controller('users')
export class UserController extends RestController {
constructor(private users: UserService) {
super();
}
@Get('/profile')
async getProfile(
@Req() req: Request,
@Res() res: Response,
): Promise<Response> {
return res.noContent();
}
}
RestController Methods
transform()
You might have noticed in the previous snippets, on how we created an instance of the transformer and ran the methods to process an output. To handle it more beautifully, you can handle it like below:
import { RestController, Request, Response } from '@app/core';
import { Controller, Get, Req, Res } from '@nestjs/common';
import { UserService } from '../services';
import { UserDetailTransformer } from '@app/transformer';
@Controller('users')
export class UserController extends RestController {
constructor(private users: UserService) {
super();
}
@Get('/profile')
async getProfile(
@Req() req: Request,
@Res() res: Response,
): Promise<Response> {
const user = await this.users.get();
return res.success(
await this.transform(user, new UserDetailTransformer, { req })
);
}
}
Notice, the {req}
object that we are passing as third param, the base RestController
itself handles reading the url and parsing the includes. Now we don't need to do the tedious task again and again. 😃
collection()
Same responsibility as the transform
method. Use this whenever you need to transform an array.
paginate()
Breaks down the obj
passed into transformed data and pagination data. Expects the obj
to include pagination
key.
If you are dealing with some other key than pagination
, you can change the key name inside paginate
method in src/core/controllers/RestController.ts file.
Route Decorators
This boilerplate comes packed with few route helpers, which you can use to make your operations easy and beautiful.
WithAlias
You can use the decorator to give an alias/name to your route.
import { RestController, Request, Response, WithAlias } from '@libs/core';
import { Controller, Get, Req, Res } from '@nestjs/common';
@Controller('users')
export class UserController extends RestController {
@Get('/profile')
@WithAlias('auth.profile')
async getProfile(
@Req() req: Request,
@Res() res: Response,
): Promise<Response> {
// ... your logic
return res.success('Success');
}
}
Now, to access the route, you can simply do
route('auth.profile')
// https://localhost:5000/users/profile
the above mentioned code will return the fully qualified url of the route. In this case, https://localhost:5000/users/profile
For dynamic routes which includes path parameters, you can pass path variables as second argument.
@Get('/books/:slug')
@WithAlias('books.detail')
async getDetail(
@Req() req: Request,
@Res() res: Response,
): Promise<Response> {
// ... your logic
return res.success({name: 'Shoe Dog', author: 'Phil Night'});
}
// now, simply do
route("books.detail", {name: "the-blue-umbrella-by-ruskin-bond"})
// https://localhost:5000/books/the-blue-umbrella-by-ruskin-bond
Extra paramters, passed will be returned as query params
route("books.detail", {name: "the-blue-umbrella-by-ruskin-bond", include:"price"})
// https://localhost:5000/books/the-blue-umbrella-by-ruskin-bond?include=price
Request
We know how tedious it can get to fetch all the input params from a request object. Nobody wants to use the req.body
, req.query
, req.params
seperately.
This boilerplate provides a decent method to get all the input params at once.
all()
Method to get the incoming parameters, all at once. No need to get body
, query
, and params
seperately every time.
const inputs = req.all();
all()
method automatically trims all strings received in the request.
Response
We have our own very generous set of api guidelines, we used our learning of multiple projects to provide structural consistency of response object (which is often unknowningly abused).
success()
Returns the success response, use this whenever your request is succesfull, usually for GET and POST requests.
Params
name | Type | Default |
---|---|---|
data | Object | -- |
status | Number | 200 |
/**
* {
* success: true,
* code: 200,
* data: { message: "Hello There" }
* };
**/
return res.success({ message: 'Hello there!' });
error()
Returns the error response, used in exception filter.
Params
name | Type | Default |
---|---|---|
error | Object or string | -- |
status | Number | 401 |
/**
* {
* success: false,
* code: 401,
* message: 'Unauthorized'
* };
**/
return res.error('Unauthorized!');
noContent()
There are cases when we need to send only a success status code and no body. noContent()
will come in handy for you.
// will return a response with status code of 204
return res.noContent();
withMeta()
There can be some case where we need to send some payload to support our requested data. For example, pagination information incase of a paginated response. withMeta
helps you achieve the same.
Params
name | Type | Default |
---|---|---|
data | Object | -- |
status | Number | 200 |
/**
* {
* success: true,
* code: 200,
* data:[{},{},{}]
* meta: {
* pagination: {
* totalPages: 10,
* currentPage: 2,
* },
* ...some other custom attributes
* }
* };
**/
return res.withMeta({
data: [{}, {}],
pagination: { totalPages: 10, currentPage: 2 },
});