上一篇我们让 API 的参数能够顺利显示在 Swagger UI 中,在设计完参数之後,我们可以针对 API 做分类,甚至把请求与回应的相关内容也设计至 Swagger UI 上。
这个功能是用来将 API 进行分类,透过 @ApiTags
装饰器就可以将特定的 Controller 打上标签,在 Swagger UI 上更容易找到对应的 API。
我们修改一下 TodoController
的内容,将 @ApiTags
套用上去,并指定标签为 Todo
:
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { ApiBody, ApiTags } from '@nestjs/swagger';
import { TodoService } from './todo.service';
import { CreateTodoDto } from './dto/create-todo.dto';
// 添加标签
@ApiTags('Todo')
@Controller('todos')
export class TodoController {
constructor(private readonly todoService: TodoService) {}
@Post()
createTodo(@Body() data: CreateTodoDto) {
return this.todoService.createTodo(data);
}
@ApiBody({ type: [CreateTodoDto] })
@Post('bulk')
createTodos(@Body() todos: CreateTodoDto[]) {
return todos.map((todo) => this.todoService.createTodo(todo));
}
@Get(':id')
getTodo(@Param('id') id: string) {
return this.todoService.getTodo(id);
}
}
透过浏览器查看 http://localhost:3000/api 会发现多了一个 Todo
的区块,里面有 TodoController
设计的 API:
这个功能让 API 在 Swagger UI 上可以有一个介面去配置特定 Header 的内容,透过 @ApiHeader
装饰器给定 name
属性,就能在 UI 上看到该栏位。
修改一下 TodoController
的内容,在 getTodo
套用 @ApiHeader
装饰器,并指定 name
为 X-Custom
:
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { ApiBody, ApiHeader, ApiTags } from '@nestjs/swagger';
import { TodoService } from './todo.service';
import { CreateTodoDto } from './dto/create-todo.dto';
@ApiTags('Todo')
@Controller('todos')
export class TodoController {
constructor(private readonly todoService: TodoService) {}
@Post()
createTodo(@Body() data: CreateTodoDto) {
return this.todoService.createTodo(data);
}
@ApiBody({ type: [CreateTodoDto] })
@Post('bulk')
createTodos(@Body() todos: CreateTodoDto[]) {
return todos.map((todo) => this.todoService.createTodo(todo));
}
// 在 Swagger UI 上可以看到 X-Custom 的栏位可以填写
@ApiHeader({
name: 'X-Custom',
description: 'Try to set custom header.',
})
@Get(':id')
getTodo(@Param('id') id: string) {
return this.todoService.getTodo(id);
}
}
透过浏览器查看 http://localhost:3000/api 会看到下方结果:
这个功能可以在 Swagger UI 上显示该 API 回传的各个 HttpCode 是什麽意思,透过 @ApiResponse
装饰器给定 status
与 description
即可。
修改 TodoController
的内容,在 createTodo
上套用 @ApiResponse
并指定 status
为 HttpStatus.CREATED
:
import { Body, Controller, Get, HttpStatus, Param, Post } from '@nestjs/common';
import { ApiBody, ApiHeader, ApiResponse, ApiTags } from '@nestjs/swagger';
import { TodoService } from './todo.service';
import { CreateTodoDto } from './dto/create-todo.dto';
@ApiTags('Todo')
@Controller('todos')
export class TodoController {
constructor(private readonly todoService: TodoService) {}
// 在 Swagger UI 上可以看到状态 201 的描述
@ApiResponse({
status: HttpStatus.CREATED,
description: 'The todo has been successfully created.',
})
@Post()
createTodo(@Body() data: CreateTodoDto) {
return this.todoService.createTodo(data);
}
@ApiBody({ type: [CreateTodoDto] })
@Post('bulk')
createTodos(@Body() todos: CreateTodoDto[]) {
return todos.map((todo) => this.todoService.createTodo(todo));
}
@ApiHeader({
name: 'X-Custom',
description: 'Try to set custom header.',
})
@Get(':id')
getTodo(@Param('id') id: string) {
return this.todoService.getTodo(id);
}
}
透过浏览器查看 http://localhost:3000/api 会看到状态 201
的描述为 The todo has been successfully created.
:
事实上 Nest 有将各种状态独立包装起来,共有以下这几个,有兴趣可以自行实验看看:
@ApiOkResponse
@ApiCreatedResponse
@ApiAcceptedResponse
@ApiNoContentResponse
@ApiMovedPermanentlyResponse
@ApiBadRequestResponse
@ApiUnauthorizedResponse
@ApiNotFoundResponse
@ApiForbiddenResponse
@ApiMethodNotAllowedResponse
@ApiNotAcceptableResponse
@ApiRequestTimeoutResponse
@ApiConflictResponse
@ApiTooManyRequestsResponse
@ApiGoneResponse
@ApiPayloadTooLargeResponse
@ApiUnsupportedMediaTypeResponse
@ApiUnprocessableEntityResponse
@ApiInternalServerErrorResponse
@ApiNotImplementedResponse
@ApiBadGatewayResponse()
@ApiServiceUnavailableResponse
@ApiGatewayTimeoutResponse
@ApiDefaultResponse
如果 API 需要经过授权才能使用的话,在 Swagger 要如何添加授权机制呢?可以透过指定的装饰器来实作,让开发人员可以在 Swagger UI 上配置授权资讯来存取 API,非常实用的功能!下面我会挑选三个授权方法进行解说:
使用 Basic
授权方法,透过 @ApiBasicAuth
装饰器将要授权的 API 套上此装饰器,并呼叫 DocumentBuilder
实例中的 addBasicAuth
方法来将授权栏位开启。
修改 TodoController
的内容,在 TodoController
带上 @ApiBasicAuth
装饰器:
import { Body, Controller, Get, HttpStatus, Param, Post } from '@nestjs/common';
import { ApiBasicAuth, ApiBody, ApiHeader, ApiResponse, ApiTags } from '@nestjs/swagger';
import { TodoService } from './todo.service';
import { CreateTodoDto } from './dto/create-todo.dto';
// Basic Auth
@ApiBasicAuth()
@ApiTags('Todo')
@Controller('todos')
export class TodoController {
constructor(private readonly todoService: TodoService) {}
@ApiResponse({
status: HttpStatus.CREATED,
description: 'The todo has been successfully created.',
})
@Post()
createTodo(@Body() data: CreateTodoDto) {
return this.todoService.createTodo(data);
}
@ApiBody({ type: [CreateTodoDto] })
@Post('bulk')
createTodos(@Body() todos: CreateTodoDto[]) {
return todos.map((todo) => this.todoService.createTodo(todo));
}
@ApiHeader({
name: 'X-Custom',
description: 'Try to set custom header.',
})
@Get(':id')
getTodo(@Param('id') id: string) {
return this.todoService.getTodo(id);
}
}
接着修改 main.ts
,呼叫 builder
的 addBasicAuth
方法:
import { NestFactory } from '@nestjs/core';
import { INestApplication } from '@nestjs/common';
import { DocumentBuilder, SwaggerCustomOptions, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
setupSwagger(app);
await app.listen(3000);
}
function setupSwagger(app: INestApplication) {
const builder = new DocumentBuilder();
const config = builder
.setTitle('TodoList')
.setDescription('This is a basic Swagger document.')
.setVersion('1.0')
.addBasicAuth() // 开启授权栏位
.build();
const document = SwaggerModule.createDocument(app, config);
const options: SwaggerCustomOptions = {
explorer: true,
};
SwaggerModule.setup('api', app, document, options);
}
bootstrap();
透过浏览器查看 http://localhost:3000/api 会发现 Todo
区块的 API 都有了锁头符号,这表示需要经过授权才能呼叫,可以透过画面上的 Authorize
按钮来填入授权资讯:
使用 Bearer
授权方法,透过 @ApiBearerAuth
装饰器将要授权的 API 套上此装饰器,并呼叫 DocumentBuilder
实例中的 addBearerAuth
方法来将授权栏位开启。
修改 TodoController
的内容,在 TodoController
带上 @ApiBearerAuth
装饰器:
import { Body, Controller, Get, HttpStatus, Param, Post } from '@nestjs/common';
import { ApiBearerAuth, ApiBody, ApiHeader, ApiResponse, ApiTags } from '@nestjs/swagger';
import { TodoService } from './todo.service';
import { CreateTodoDto } from './dto/create-todo.dto';
// Bearer Auth
@ApiBearerAuth()
@ApiTags('Todo')
@Controller('todos')
export class TodoController {
constructor(private readonly todoService: TodoService) {}
@ApiResponse({
status: HttpStatus.CREATED,
description: 'The todo has been successfully created.',
})
@Post()
createTodo(@Body() data: CreateTodoDto) {
return this.todoService.createTodo(data);
}
@ApiBody({ type: [CreateTodoDto] })
@Post('bulk')
createTodos(@Body() todos: CreateTodoDto[]) {
return todos.map((todo) => this.todoService.createTodo(todo));
}
@ApiHeader({
name: 'X-Custom',
description: 'Try to set custom header.',
})
@Get(':id')
getTodo(@Param('id') id: string) {
return this.todoService.getTodo(id);
}
}
接着修改 main.ts
,呼叫 builder
的 addBearerAuth
方法:
import { NestFactory } from '@nestjs/core';
import { INestApplication } from '@nestjs/common';
import { DocumentBuilder, SwaggerCustomOptions, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
setupSwagger(app);
await app.listen(3000);
}
function setupSwagger(app: INestApplication) {
const builder = new DocumentBuilder();
const config = builder
.setTitle('TodoList')
.setDescription('This is a basic Swagger document.')
.setVersion('1.0')
.addBearerAuth() // 开启授权栏位
.build();
const document = SwaggerModule.createDocument(app, config);
const options: SwaggerCustomOptions = {
explorer: true,
};
SwaggerModule.setup('api', app, document, options);
}
bootstrap();
透过浏览器查看 http://localhost:3000/api 效果与 Basic
相同,差别在於授权方式不同:
使用 OAuth2
授权方法,透过 @ApiOAuth2
装饰器将要授权的 API 套上此装饰器,并呼叫 DocumentBuilder
实例中的 addOAuth2
方法来将授权栏位开启,但这里需要特别设置 type
与 flow
参数来完成。
修改 TodoController
的内容,在 TodoController
带上 @ApiOAuth2
装饰器:
import { Body, Controller, Get, HttpStatus, Param, Post } from '@nestjs/common';
import { ApiBody, ApiHeader, ApiOAuth2, ApiResponse, ApiTags } from '@nestjs/swagger';
import { TodoService } from './todo.service';
import { CreateTodoDto } from './dto/create-todo.dto';
// OAuth2 Auth
@ApiOAuth2(['write', 'read', 'update'])
@ApiTags('Todo')
@Controller('todos')
export class TodoController {
constructor(private readonly todoService: TodoService) {}
@ApiResponse({
status: HttpStatus.CREATED,
description: 'The todo has been successfully created.',
})
@Post()
createTodo(@Body() data: CreateTodoDto) {
return this.todoService.createTodo(data);
}
@ApiBody({ type: [CreateTodoDto] })
@Post('bulk')
createTodos(@Body() todos: CreateTodoDto[]) {
return todos.map((todo) => this.todoService.createTodo(todo));
}
@ApiHeader({
name: 'X-Custom',
description: 'Try to set custom header.',
})
@Get(':id')
getTodo(@Param('id') id: string) {
return this.todoService.getTodo(id);
}
}
接着修改 main.ts
,呼叫 builder
的 addOAuth2
方法,将 type
指定为 oauth2
,flow
则是添加 implicit
参数并配置 authorizationUrl
、tokenUrl
以及 scopes
:
import { NestFactory } from '@nestjs/core';
import { INestApplication } from '@nestjs/common';
import { DocumentBuilder, SwaggerCustomOptions, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
setupSwagger(app);
await app.listen(3000);
}
function setupSwagger(app: INestApplication) {
const builder = new DocumentBuilder();
const config = builder
.setTitle('TodoList')
.setDescription('This is a basic Swagger document.')
.setVersion('1.0')
.addOAuth2({
type: 'oauth2',
flows: {
implicit: {
authorizationUrl: '<AUTHORIZATION_URL>', // 授权位址
tokenUrl: '<TOKEN_URL>', // 授权用 token
scopes: { // 权限选项
read: 'read',
write: 'write',
update: 'update',
delete: 'delete',
},
},
},
})
.build();
const document = SwaggerModule.createDocument(app, config);
const options: SwaggerCustomOptions = {
explorer: true,
};
SwaggerModule.setup('api', app, document, options);
}
bootstrap();
透过浏览器查看 http://localhost:3000/api 效果与 Basic
相同,但在授权资讯配置那里会有差异,Swagger 会向该服务请求授权:
Swagger UI 设计的好坏会影响整体开发人员的效率,只要善用上一篇学到的 参数设计 以及本篇讲解的 操作设计 与 授权设计,就可以大幅降低前後端的沟通成本,绝对是当今非常值得学习的工具!这里附上今天的懒人包:
@ApiTags
将 API 进行分类。@ApiHeader
开启指定的 Header 栏位。@ApiResponses
可以在 Swagger UI 上显示该 API 回传的各个 HttpCode 是什麽意思。@ApiOkResponse
。@ApiBasicAuth
、@ApiBearerAuth
以及 @ApiOAuth2
。DocumentBuilder
实例呼叫对应的授权机制方法,来开启授权栏位。
<<: Day27 - 云端交易主机 - Ubuntu SSH登入 & 远端桌面
制定程序码格式规范对於可读性来说是必须的,如果开发者写程序时都有各自的格式规范,那整个专案的程序码会...
延续之前的浏览列的实作,这次要增加登入跟注册纽,其实我也还在想这个网站是否需要注册功能,毕竟是私人社...
在昨日的文章中,简单地向各位展示直接藉由Function抓取API 所能得到的架构会是何者 而今天...
还记得我们在 Day 09、Day 10 有 2 个自制版本的 createMacine [Day ...
15 天了,没想到过半了,再接再厉~~ 讲了几天的 React , 现在让我们把焦点拉回 React...