前言

swagger这东东,萝卜青菜各有所爱吧.

反正我呆的公司用这个,我用的也还行!
有兴趣的可以瞅瞅~

说说优点吧,
可以精确的展示每个字段意义,只要注解写的到位!
schema也能正常读取!还能直接测试接口!

效果图

以下就是配置好及写一些demo接口所展示的效果;
包括语法高亮,api分组,响应注解,api废弃,接口概述等~

实战

安装

# 前者是swagger的nest module,官方团队维护的
# 后者是适配express的swagger ui库
# 库用新不用旧,语法会有所差异!
yarn add @nestjs/swagger swagger-ui-express

配置

抽离的环境变量(dev.local.env)

# ------- Node服务相关 ---------------------
# Node服务启动监听的端口
SERVE_LISTENER_PORT=3000# ------- Swagger相关 ---------------------
# Swagge Api文档访问路径
SWAGGER_SETUP_PATH=api-docs
# 标题及描述
SWAGGER_UI_TITLE=氚云3.0 BFF文档
SWAGGER_UI_TITLE_DESC=一点寒芒先到,随后枪出如龙
# API版本
SWAGGER_API_VERSION=1.0
# Swagger Api Prefix
SWAGGER_ENDPOINT_PREFIX=api/v1# ------- 开发模式相关 ---------------------
NODE_ENV=development

用工厂函数组装配置!

import { registerAs } from '@nestjs/config';
export interface EnvSwaggerOptions {title: string;setupUrl: string;desc?: string;prefix: string;version: string;
}
export default registerAs('EnvSwaggerOptions',(): EnvSwaggerOptions => ({title: process.env.SWAGGER_UI_TITLE, // swagger标题desc: process.env.SWAGGER_UI_TITLE_DESC, // swagger描述version: process.env.SWAGGER_API_VERSION, // swagger api 版本,自定义的setupUrl: process.env.SWAGGER_SETUP_PATH, // UI文档路径prefix: process.env.SWAGGER_ENDPOINT_PREFIX, // 接口聚合前缀,在nest用全局prefix,但是丢给swagger定义也不冲突}),
);

代码入口(main.ts)

熟悉的味道,还是把一些配置抽里成环境变量,
外部维护,通过注册中心使用~~
老规矩,从typescript声明入手~~~

import { INestApplication } from '@nestjs/common';
import { OpenAPIObject, SwaggerCustomOptions, SwaggerDocumentOptions } from './interfaces';
export declare class SwaggerModule {static createDocument(app: INestApplication, config: Omit<OpenAPIObject, 'paths'>, options?: SwaggerDocumentOptions): OpenAPIObject;static setup(path: string, app: INestApplication, document: OpenAPIObject, options?: SwaggerCustomOptions): void;private static setupExpress;private static setupFastify;
}import { OpenAPIObject } from './interfaces';
import { ExternalDocumentationObject, SecuritySchemeObject, ServerVariableObject } from './interfaces/open-api-spec.interface';
export declare class DocumentBuilder {private readonly logger;private readonly document;setTitle(title: string): this;  // 设置swagger ui标题setDescription(description: string): this; // 设置swagger ui描述setVersion(version: string): this; // 设置swagger ui版本setTermsOfService(termsOfService: string): this; // 设置条例链接,可以单纯理解为一个外链setContact(name: string, url: string, email: string): this; // 联系信息setLicense(name: string, url: string): this; // 采用的协议,比如MIT等等// 若是用到了外部nginx这类接口,这个可以拼接请求域addServer(url: string, description?: string, variables?: Record<string, ServerVariableObject>): this; setExternalDoc(description: string, url: string): this; // 设置外部文档链接setBasePath(path: string): this; // 可以理解为聚合前缀,在nest有自己的api可以用,可以忽略设置这个addTag(name: string, description?: string, externalDocs?: ExternalDocumentationObject): this; // 添加swagger分类addSecurity(name: string, options: SecuritySchemeObject): this; // 以下都是鉴权安全性相关的addSecurityRequirements(name: string, requirements?: string[]): this; // ...addBearerAuth(options?: SecuritySchemeObject, name?: string): this;// Bearer 认证addOAuth2(options?: SecuritySchemeObject, name?: string): this;// OAuth2 认证addApiKey(options?: SecuritySchemeObject, name?: string): this;// addBasicAuth(options?: SecuritySchemeObject, name?: string): this;// 基础认证addCookieAuth(cookieName?: string, options?: SecuritySchemeObject, securityName?: string): this; // Cookie 认证build(): Omit<OpenAPIObject, 'components' | 'paths'>; // 读取设置好的配置构建出swagger的集中化配置
}export interface SwaggerDocumentOptions {include?: Function[]; // 手动指定包含的模块extraModels?: Function[]; // 额外的model定义需和上面的关联,也就是存在include里面的ignoreGlobalPrefix?: boolean; // 这个设置为true,会忽略setGlobalPrefix的设置deepScanRoutes?: boolean; // 开启这个,只要是import的都会追加的索引的路由// 操作id,可以通过这个工厂函数来改变id的定义(接口请求生成)// 默认走的是@default () => controllerKey_methodKey, 模块_方法operationIdFactory?: (controllerKey: string, methodKey: string) => string;
}export interface SwaggerCustomOptions {explorer?: boolean; // 开了没啥效果swaggerOptions?: any; // swagger ui的配置customCss?: string; // 自定义csscustomCssUrl?: string; // 自定义css 链接customJs?: string; // 同上,jscustomfavIcon?: string;// 同上,小图标swaggerUrl?: string; // swagger链接设置customSiteTitle?: string; // 自定义网站标题validatorUrl?: string; // 远程校验url,一般用不到url?: string;// 指向API定义的URL(通常是swagger。json或swagger.yaml)。如果使用url或规范,将被忽略。urls?: Record<'url' | 'name', string>[];// 没用过
}
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';
import { EnvSwaggerOptions } from './config/env/swagger.config';
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from './common/pipes/validataion.pipe';
async function bootstrap() {const app = await NestFactory.create(AppModule, {cors: false,logger: false,});const configService = app.get(ConfigService);const swaggerOptions = configService.get<EnvSwaggerOptions>('EnvSwaggerOptions',);// 设置全局请求访问前缀app.setGlobalPrefix(swaggerOptions.prefix);const options = new DocumentBuilder().setExternalDoc('xxxxx前端文档 ','htxxxxx').setTitle(swaggerOptions.title).setDescription(swaggerOptions.desc).setVersion(swaggerOptions.version).addBearerAuth().build();const document = SwaggerModule.createDocument(app, options);SwaggerModule.setup(swaggerOptions.setupUrl, app, document, {customSiteTitle: swaggerOptions.title,swaggerOptions: {explorer: true,docExpansion: 'list',filter: true,showRequestDuration: true,syntaxHighlight:{active:true,theme:"tomorrow-night"}}});await app.listen(configService.get('SERVE_LISTENER_PORT'));
}
bootstrap()

注解介绍

用于DTO的注解

也就是用来生成modal(字段的解释)

  • @ApiProperty () : @ApiProperty({ required:false}) 就等同于下面,
  • @ApiPropertyOptional() : 这个是上个基础上把必填变成选填

我们看下typescript的声明~~~

// 相当直观,大多数类型的及区间的限制都能一目了然
export interface SchemaObject {nullable?: boolean;discriminator?: DiscriminatorObject;readOnly?: boolean;writeOnly?: boolean;xml?: XmlObject;externalDocs?: ExternalDocumentationObject;example?: any;examples?: any[];deprecated?: boolean;type?: string;allOf?: (SchemaObject | ReferenceObject)[];oneOf?: (SchemaObject | ReferenceObject)[];anyOf?: (SchemaObject | ReferenceObject)[];not?: SchemaObject | ReferenceObject;items?: SchemaObject | ReferenceObject;properties?: Record<string, SchemaObject | ReferenceObject>;additionalProperties?: SchemaObject | ReferenceObject | boolean;description?: string;format?: string;default?: any;title?: string;multipleOf?: number;maximum?: number;exclusiveMaximum?: boolean;minimum?: number;exclusiveMinimum?: boolean;maxLength?: number;minLength?: number;pattern?: string;maxItems?: number;minItems?: number;uniqueItems?: boolean;maxProperties?: number;minProperties?: number;required?: string[];enum?: any[];
}
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';export enum UserRole {Boss="后门",Admin = '管理员',User = '常规用户',
}export class CreateAppDto {@ApiPropertyOptional({description: '姓名',})readonly name?: string;@ApiProperty({ description: '年龄', minimum: 0, maximum: 130 })readonly age: number;@ApiPropertyOptional({description: '爱好',})readonly hobit: string;@ApiProperty({ enum: ['Boss', 'Admin', 'User']})role: UserRole;}

用于业务逻辑的

这个就好多了,有具体到接口回来,异常等等;
常规Response用ApiResponse就能满足很多场景,
schame,状态码都能定义~~~
具体可以跳进去看typescript,我们举个栗子!

import { Controller, Get, Post, HttpCode, Body, Query } from '@nestjs/common';
import {ApiCreatedResponse,ApiHeader,ApiInternalServerErrorResponse,ApiOkResponse,ApiOperation,ApiParam,ApiQuery,ApiResponse,
} from '@nestjs/swagger';
import { CreateAppDto, FindOneParams, UserRole } from './app.dto';
import { AppService } from './app.service';@Controller()
export class AppController {constructor(private readonly appService: AppService) {}@Get()getHello(): string {return this.appService.getHello();}@ApiHeader({name: 'Authorization',description: 'Auth token',})@ApiCreatedResponse({description: '链接成功创建,其实就是201状态的描述',})@Post('/post')@HttpCode(200)@ApiParam({ name: 'name', description: '名字', type: CreateAppDto })postParams(@Body() param: CreateAppDto): string {return '测试参数' + JSON.stringify(param);}@Get('/user')@ApiOperation({tags: ['获取用户信息'],description: '获取用户信息',deprecated: true,})@ApiQuery({ name: 'id', description: '用户id' })@ApiResponse({ description: '成功请求回来,其实就是200的描述', status: 200 })@ApiInternalServerErrorResponse({ description: '服务端异常' })updateApp(@Query() query: FindOneParams) {return JSON.stringify(query);}@Get('/netease-news/:id')@ApiOkResponse({ description: '成功请求回来' })@ApiQuery({ name: 'id', description: '用户id', required: false })async async(@Body() body) {const res = await this.appService.getNetEaseNew('https://anapioficeandfire.com/api/characters/583',{ data: body },);return res.data;}@ApiQuery({ name: 'role', enum: UserRole })@ApiOperation({tags: ['返回角色信息'],description: '返回角色信息',})@Get('/role')async filterByRole(@Query('role') role: UserRole = UserRole.User) {return role;}
}

总结

到此,基本可以边写代码及文档输出了,
只要注解用的好,swagger都能如期输出!

有不对之处请留言,会及时修正!谢谢阅读~

NestJS 7.x 折腾记: (4) Swagger接入及相关用法相关推荐

  1. NestJS 7.x 折腾记: (3) 采用nestjs-pino作为Nest logger

    前言 内置的logger不是很满足个人的需求, 所以找了下社区主流的日志实现, 从log4js,winston, 到选型pino . 是另外两个不好么,那倒不是. 萝卜青菜各有所爱吧, pino够轻量 ...

  2. NestJS 6.x折腾记- (0) 开胃菜, TypeORM 连接远程的MySQL(ssh tunnel)及Linux信息过滤裁切基础

    前言 昨天发现的框架,看了下官方文档,号称Nodejs版本的spring(java) 开发模式有ng6既视感,这对有ng经验的小伙伴来说,莫名的亲切- 适合尝尝鲜,目前有1W+ star, 上正式线我 ...

  3. NestJS 7.x 折腾记: (5) 管道,一个好玩的东西!比如入参校验!

    前言 管道这个词,若是有玩过Linux的小伙伴肯定知晓,比如(看图): 意思就git的提交记录以单行显示的前三条,而且提交概要中有build这个词的~ 在nest里面的管道,主要是用来做入参数据类型的 ...

  4. NestJS 7.x 折腾记: (6) 异常过滤器,取其精华去其糟粕!比如响应异常数据的包装~

    前言 正如官方所说: 内置的异常层负责处理整个应用程序中的所有抛出的异常. 当捕获到未处理的异常时,最终用户将收到友好的响应. NestJS提供了一波拿来即用的内置异常过滤器; 在@nestjs/co ...

  5. linux卸载桌面Ubuntu,Ubuntu安装卸载KDE桌面之折腾记

    记得几年前刚开始用的是OpenSUSE,桌面环境好像是KED1.5的,经常性崩溃阿,太让人无语了,动不动就崩溃,但是对Linux也不熟悉,没有比较好的方法,后来就转Ubuntu了. 今天看到nenew ...

  6. n1运行linux,斐讯N1折腾记:运行 Linux 及优化

    此教程同样适用于斐讯 P1 咳咳咳,上篇教程教大家给斐讯 N1 降级并且刷了官改系统,可以当作一个电视盒子和下载机来使用. 有些小伙伴可能不想把它当作电视盒子,就想把它当作 NAS 或者是服务器,但是 ...

  7. React 折腾记 - (4) 侧边栏联动Tabs菜单-增强版(结合Mobx)

    前言 有小伙伴留言有前进后退没法联动的问题.我仔细梳理下了. 简化了代码逻辑和代码量,重写了一遍,执行逻辑和上个版本有所差异; 上个版本 :React 折腾记 - (3) 结合Mobx实现一个比较靠谱 ...

  8. React 折腾记 - (1) React Router V4 和antd侧边栏的正确关联及动态title的实现

    前言 一如既往,实战出真理. 有兴趣的可以瞧瞧,没兴趣的大佬请止步于此. 免得浪费您的时间 效果图 基于antd的sidebar组件封装 折腾记的技术栈选型 Mobx & mobx-react ...

  9. rtl8811au黑苹果10.15_荣耀MagicBook I5黑苹果折腾记(超详细教程与排坑)

    本文主要介绍如何安装Win10 + Mac OS双系统,以及安装过程中可能遇到的一些坑. 本人的机型是:MagicBook I5-8250U MX150独显 8GB+256GB (VLT-W50),更 ...

最新文章

  1. 【Ant Design Pro 二】 创建页面,组件,并在页面调用
  2. Boost::context模块callcc的jump测试程序
  3. 慌了,居然被问到怎么做高并发系统的限流
  4. maven+jetty项目在tomcat部署
  5. 卷积神经网络计算题试题_卷积神经网络的计算
  6. xrdp完美实现Windows远程访问Ubuntu 16.04
  7. 阿里第一颗芯片问世,平头哥发布最强AI芯片含光800
  8. array.unshift_Ruby中带有示例的Array.unshift()方法
  9. java c 面向对象比较教程_c语言初学指针,对于java面向对象的初理解
  10. android如何使用BroadcastReceiver后台实现来电通话记录的监听并存取到sqllite数据库通过Contentprovilder实现接口...
  11. react-native---配置reactnative报红,run-Android时候报错unable to load script from assets 'index.android.bundl
  12. tomcat 停止 java 线程不停止_Java Tomcat,底层Netty线程不停止
  13. 学习git reset 、 git checkout、git revert
  14. 30 | 答疑文章(二):用动态的观点看加锁
  15. 应用程序无法启动,因为应用程序的并行配置不正确 解决方案
  16. 实验:Android案例——小宝宝装备选择
  17. 使用Springboot+MAVEN完成SSM项目的搭建(idea)--小白面试机试题
  18. 看了 web.dev 的 631 篇博客,我总结了这些内容
  19. php微信支付返回值,php微信支付全记录
  20. 广汽丰田-“饮水思源”活动专题网站

热门文章

  1. js 数字递增递减_JavaScript如何实现数字递增特效
  2. python语音程序设计教程_Python语言程序设计教程
  3. 刷脸支付人工智能和商业领域进一步融合
  4. 函数平移口诀_二次函数平移规律口诀
  5. c语言求解三角形的重心,计算几个三角形的重心
  6. ~5 ccf 2021-12-2 序列查询新解
  7. Swift - 判等
  8. 解决在VSCode上使用Vetur插件格式化Vue代码时,会出现单引号和结尾冒号问题
  9. 什么叫“我是搞计算机的”?
  10. 截至20161210深市股票代码和名称