-
-
Notifications
You must be signed in to change notification settings - Fork 572
Controllers
@nestjsx/crud - core package which provides @Crud()
controller decorator for endpoints generation, global configuration, validation, helper decorators.
npm i @nestjsx/crud class-transformer class-validator
Let's take a look at the example of using @nestjsx/crud
with TypeORM.
Assume we have some TypeORM enitity:
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class Company {
@PrimaryGeneratedColumn() id: number;
@Column() name: string;
}
Then we need to create a service:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';
import { Company } from './company.entity';
@Injectable()
export class CompaniesService extends TypeOrmCrudService<Company> {
constructor(@InjectRepository(Company) repo) {
super(repo);
}
}
We've done with the service so let's create a controller:
import { Controller } from '@nestjs/common';
import { Crud } from '@nestjsx/crud';
import { Company } from './company.entity';
import { CompaniesService } from './companies.service';
@Crud({
model: {
type: Company,
},
})
@Controller('companies')
export class CompaniesController {
constructor(public service: CompaniesService) {}
}
All we have to do next is to connect our service and controller in the CompaniesModule
as we usually do:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Company } from './company.entity';
import { CompaniesService } from './companies.service';
import { CompaniesController } from './companies.controller';
@Module({
imports: [TypeOrmModule.forFeature([Company])],
providers: [CompaniesService],
exports: [CompaniesService],
controllers: [CompaniesController],
})
export class CompaniesModule {}
That's it.
Crud()
decorator generates the following API endpoints:
GET /heroes
GET /heroes/:heroId/perks
Result: array of resources | pagination object with data
Status Codes: 200
GET /heroes/:id
GET /heroes/:heroId/perks:id
Request Params: :id
- some resource field (slug)
Result: resource object | error object
Status Codes: 200 | 404
POST /heroes
POST /heroes/:heroId/perks
Request Body: resource object | resource object with nested (relational) resources
Result: created resource object | error object
Status Codes: 201 | 400
POST /heroes/bulk
POST /heroes/:heroId/perks/bulk
Request Body: array of resources objects | array of resources objects with nested (relational) resources
{
"bulk": [{ "name": "Batman" }, { "name": "Batgirl" }]
}
Result: array of created resources | error object
Status codes: 201 | 400
PATCH /heroes/:id
PATCH /heroes/:heroId/perks/:id
Request Params: :id
- some resource field (slug)
Request Body: resource object (or partial) | resource object with nested (relational) resources (or partial)
Result:: updated partial resource object | error object
Status codes: 200 | 400 | 404
DELETE /heroes/:id
DELETE /heroes/:heroId/perks/:id
Request Params: :id
- some resource field (slug)
Result:: empty | resource object | error object
Status codes: 200 | 404
Crud()
decorator accepts the following options:
{
model: {
type: Entity|Model|DTO
},
}
Required
Entity
, Model
or DTO
class must be provided here. Everything else described bellow is optional. It's needed for a built in validation based on NestJS ValidationPipe
.
{
validation?: ValidationPipeOptions | false;
}
Optional
Accepts ValidationPipe
options or false
if you want to use your own validation implementation.
{
params?: {
[key: string]: {
field: string;
type: 'number' | 'string' | 'uuid';
primary?: boolean;
},
},
}
Optional
By default @Crud()
decorator will use id
with the type number
as a primary slug param.
If you have, for instance, a resorce field called slug
or whatever, it's a UUID and you need it to be a primary slug by which your resource should be fetched, you can set up this params options:
{
params: {
slug: {
field: 'slug',
type: 'uuid',
primary: true,
},
},
}
If you have a controller path with that looks kinda similar to this /companies/:companyId/users
you need to add this param option:
{
params: {
...
companyId: {
field: 'companyId',
type: 'number'
},
},
}
{
routes?: {
getManyBase?: {
interceptors?: [],
decorators?: [],
},
getOneBase?: {
interceptors?: [],
decorators?: [],
},
createOneBase?: {
interceptors?: [],
decorators?: [],
},
createManyBase?: {
interceptors?: [],
decorators?: [],
},
updateOneBase: {
interceptors?: [],
decorators?: [],
allowParamsOverride?: boolean,
},
deleteOneBase?: {
interceptors?: [],
decorators?: [],
returnDeleted?: boolean,
},
}
}
Optional
It's a set of options for each of the generated routes.
interceptors
- an array of your custom interceptors
decorators
- an array of your custom decorators
allowParamsOverride
- whether or not to allow body data be overriten by the URL params on PATH request. Default: false
returnDeleted
- whether or not an entity object should be returned in the response body on DELETE request. Default: false
{
query?: {
allow?: string[];
exclude?: string[];
persist?: string[];
filter?: QueryFilter[];
join?: JoinOptions;
sort?: QuerySort[];
limit?: number;
maxLimit?: number;
cache?: number | false;
}
}
Optional
It's a set of query options fro GET request.
{
allow: ['name', 'email'];
}
Optional
An Array of fields that are allowed to be received in GET requests. If empty or undefined - allow all.
{
exclude: ['accessToken'];
}
Optional
An Array of fields that will be excluded from the GET response (and not queried from the DB).
{
persist: ['createdAt'];
}
Optional
An Array of fields that will be always persisted in GET response.
{
filter: [
{
field: 'isActive',
operator: 'ne',
value: false,
},
];
}
Optional
An Array of filter
objects that will be merged (combined) with query filter
if those are passed in GET request. If not - filter
will be added to the DB query as a stand-alone condition.
If multiple items are added, they will be interpreted as AND
type of conditions.
{
join: {
profile: {
persist: ['name'],
eager: true,
},
tasks: {
allow: ['content'],
},
notifications: {
exclude: ['token']
},
company: {},
'company.projects': {
persist: ['status']
},
'users.projects.tasks': {
exclude: ['description'],
},
}
}
Optional
An Object of relations that allowed to be fetched by passing join
query parameter in GET requests.
Each key of join
object must strongly match the name of the corresponding resource relation. If particular relation name is not present in this option, then user will not be able to get this relational objects in GET request.
Each relation option can have (all below are optional):
allow
- an Array of fields that are allowed to be received in GET requests. If empty or undefined - allow all.
exclude
- an Array of fields that will be excluded from the GET response (and not queried from the DB).
persist
- an Array of fields that will be always persisted in GET response.
eager
- type boolean
- whether or not current relation should persist in every GET response.
{
sort: [
{
field: 'id',
order: 'DESC',
},
];
}
Optional
An Array of sort
objects that will be merged (combined) with query sort
if those are passed in GET request. If not - sort
will be added to the DB query as a stand-alone condition.
{
limit: 25,
}
Optional
Default limit
that will be aplied to the DB query.
{
maxLimit: 100,
}
Optional
Max amount of results that can be queried in GET request.
Notice: it's strongly recommended to set up this option. Otherwise DB query will be executed without any LIMIT if no limit
was passed in the query or if the limit
option hasn't been set up in crud options.
{
cache: 2000,
}
Optional
If Caching Results
is implemented on you project, then you can set up default cache
in milliseconds for GET response data.
Cache can be reseted by using cache=0
query parameter in your GET requests.