Route Decorators
Route decorators are used to expose controller methods as REST API operations.If you are not familiar with the concept of Route or Controller, please seeLoopBack Route and LoopBack Controller to learnmore about them.
By calling a route decorator, you provide OpenAPI specification to describe theendpoint which the decorated method maps to. You can choose different decoratorsaccordingly or do a composition of them:
API Decorator
Syntax:@api(spec: ControllerSpec)
@api
is a decorator for the controller class and is appended just before it’sdeclared. @api
is used when you have multiplePaths Objectsthat contain all path definitions of your controller. Please note the api specsdefined with @api
will override other api specs defined inside the controller.For example:
@api({
basePath: '/',
paths: {
'/greet': {
get: {
'x-operation-name': 'greet',
'x-controller-name': 'MyController',
parameters: [{name: 'name', schema: {type: 'string'}, in: 'query'}],
responses: {
'200': {
description: 'greeting text',
content: {
'application/json': {
schema: {type: 'string'},
},
},
},
},
},
},
},
})
class MyController {
// The operation endpoint defined here will be overriden!
@get('/greet')
greet(@param.query.number('limit') name: string) {}
}
app.controller(MyController);
A more detailed explanation can be found inSpecifying Controller APIs
Operation Decorator
Syntax:@operation(verb: string, path: string, spec?: OperationObject)
@operation
is a controller method decorator. It exposes a Controller method asa REST API operation and is represented in the OpenAPI spec as anOperation Object.You can specify the verb, path, parameters, and response as a specification ofyour endpoint, for example:
const spec = {
parameters: [{name: 'name', schema: {type: 'string'}, in: 'query'}],
responses: {
'200': {
description: 'greeting text',
content: {
'application/json': {
schema: {type: 'boolean'},
},
},
},
},
};
class MyController {
@operation('HEAD', '/checkExist', spec)
checkExist(name: string) {}
}
Commonly-used Operation Decorators
Syntax:@get(path: string, spec?: OperationObject)
Same Syntax for decorators@post
,@put
,@patch
,@del
You can call these sugar operation decorators as a shortcut of @operation
. Forexample:
class MyController {
@get('/greet', spec)
greet(name: string) {}
}
is equivalent to
class MyController {
@operation('GET', '/greet', spec)
greet(name: string) {}
}
Parameter Decorator
Syntax: seeAPI documentation
@param
is applied to controller method parameters to generate an OpenAPIparameter specification for them.
For example:
import {get, param} from '@loopback/rest';
const categorySpec = {
name: 'category',
in: 'path',
required: true,
schema: {type: 'string'},
};
const pageSizeSpec = {
name: 'pageSize',
in: 'query',
required: false,
schema: {type: 'integer', format: 'int32'},
};
class MyController {
@get('Pets/{category}')
list(
@param(categorySpec) category: string,
@param(pageSizeSpec) pageSize?: number,
) {}
}
Writing the whole parameter specification is tedious, so we’ve created shortcutsto define the params with the pattern @param.${in}.${type}(${name})
:
- in: The parameter location. It can be one of the following values:
query
,header
, orpath
. - type: Acommon name of OpenAPI primitive data type.
- name: Name of the parameter. It should be a
string
.A list of available shortcuts forquery
can be found inAPI document,along with the shortcuts forpath
andheader
.
An equivalent example using the shortcut decorator would be:
class MyController {
@get('/Pets/{category}')
list(
@param.path.string('category') category: string,
@param.query.number('pageSizes') pageSize?: number,
) {}
}
You can find specific use cases inWriting Controller methods
The parameter location cookie is not supported yet, see__(https://github.com/strongloop/loopback-next/issues/997)
RequestBody Decorator
Syntax: seeAPI documentation
@requestBody()
is applied to a controller method parameter to generate OpenAPIrequestBody specification for it.
Only one parameter can be decorated by @requestBody
per controller method.
A typicalOpenAPI requestBody specificationcontains properties description
, required
, and content
:
requestBodySpec: {
description: 'a user',
required: true,
content: {
'application/json': {...schemaSpec},
'application/text': {...schemaSpec},
},
}
In order to use @requestBody
in a parameter type, the model in the parametertype must be decorated with @model
and @property
:
import {model, property} from '@loopback/repository';
import {Address} from './address.model';
@model()
class User {
@property()
firstname: string;
@property()
lastname: string;
@property()
address: Address;
}
To learn more about decorating models and the corresponding OpenAPI schema, seemodel decorators.
The model decorators allow type information of the model to be visible to thespec generator so that @requestBody
can be used on the parameter:
/src/controllers/user.controller.ts
import {User} from '../models/user.model';
import {put} from '@loopback/rest';
class UserController {
@put('/Users/{id}')
async replaceUser(
@param.path.string('id') id: string,
@requestBody() user: User,
) {}
}
For the simplest use case, you can leave the input of @requestBody
empty sincewe automatically detect the type of user
and generate the corresponding schemafor it. The default content type is set to be application/json
.
You can also customize the generated requestBody
specification in three ways:
- Add the optional fields
description
andrequired
class MyController {
@put('/Users/{id}')
async replaceUser(
@param.path.string('id') id: string,
@requestBody({
description: 'a modified user',
required: true,
})
user: User,
) {}
}
- Override the content type or define multiple content types
class MyController {
@put('/Users/{id}')
async replaceUser(
@param.path.string('id') id: string,
@requestBody({
content: {
// leave the schema as empty object, the decorator will generate it for both.
'application/text': {},
'application/xml': {},
},
})
user: User,
) {}
}
- Override the schema specification
import {UserSchema, User} from '../model/user.schema';
class MyController {
@put('/Users/{id}')
async replaceUser(
@param.path.string('id') id: string,
@requestBody({
content: {
'application/json': UserSchema,
},
})
user: User,
) {}
}
We plan to support more @requestBody
shortcuts in the future. You can trackthe feature instory 1064.
x-ts-type extension
To simplify schema definition and reference, LoopBack allows x-ts-type
extension for the OpenAPI schema object. The x-ts-type
points to a model classor simple types. It can be used for parameters, request body and responses. Forexample,
import {model, property} from '@loopback/repository';
import {requestBody, post, get} from '@loopback/openapi-v3';
@model()
class MyModel {
@property()
name: string;
}
export class MyController {
@get('/', {
responses: {
'200': {
description: 'hello world',
content: {'application/json': {schema: {'x-ts-type': MyModel}}},
},
},
})
hello() {
return 'hello world';
}
@post('/')
greet(
@requestBody({
content: {'application/json': {schema: {'x-ts-type': MyModel}}},
})
body: MyModel,
) {
return `hello ${body.name}`;
}
}
The x-ts-type
can be used for array and object properties too:
const schemaWithArrayOfMyModel = {
type: 'array',
items: {
'x-ts-type': MyModel,
},
};
const schemaDeepArrayOfMyModel = {
type: 'array',
items: {
type: 'array',
items: {
'x-ts-type': MyModel,
},
},
};
const schemaWithObjectPropOfMyModel = {
type: 'object',
properties: {
myModel: {
'x-ts-type': MyModel,
},
},
};
export class SomeController {
@post('/my-controller')
greetObjectProperty(@requestBody({
content: {'application/json': {schema: schemaWithObjectPropOfMyModel}},
})
body: {
myModel: MyModel;
}): string {
return `hello ${body.myModel.name}!`;
}
@get('/my-controllers', {
responses: {
'200': {
description: 'hello world',
content: {'application/json': {schema: schemaWithArrayOfMyModel}},
},
},
})
everyone(): MyModel[] {
return [{name: 'blue'}, {name: 'red'}];
}
@post('/my-controllers')
greetEveryone(
@requestBody({
content: {'application/json': {schema: schemaDeepArrayOfMyModel}},
})
body: MyModel[][],
): string {
return `hello ${body.map(objs => objs.map(m => m.name))}`;
}
}
When the OpenAPI spec is generated, the xs-ts-type
is mapped to{$ref: '#/components/schemas/MyModel'}
and a corresponding schema is added tocomponents.schemas.MyModel
of the spec.