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

简介: swagger这东东,萝卜青菜各有所爱吧.反正我呆的公司用这个,我用的也还行!有兴趣的可以瞅瞅~说说优点吧,可以精确的展示每个字段意义,只要注解写的到位!schema也能正常读取!还能直接测试接口!

网络异常,图片无法展示
|


前言


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; // 自定义css
    customCssUrl?: string; // 自定义css 链接
    customJs?: string; // 同上,js
    customfavIcon?: 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;
  }
}
目录
相关文章
swagger2 注解说明 @ApiImplicitParam和@ApiImplicitParams的用法
swagger2 注解说明 @ApiImplicitParam和@ApiImplicitParams的用法
97 0
|
资源调度 API
[Nestjs] 集成 Swagger
安装 Swagger 模块:首先,使用 npm 或者 yarn 安装 @nestjs/swagger 模块。
162 0
|
前端开发
小满nestjs(第二十三章 nestjs swagger接口文档)
小满nestjs(第二十三章 nestjs swagger接口文档)
164 0
小满nestjs(第二十三章 nestjs swagger接口文档)
|
Java
Swagger系列(二) ------- 极致用法
编写 SpringBoot 项目,项目中 controller 中包含一个 Handler,测试项目,保证程序可以正确运行。
61 0
Swagger系列(二) ------- 极致用法
|
4月前
|
数据可视化 Java API
Spring Boot与Swagger的集成
Spring Boot与Swagger的集成
|
4月前
|
Java API 开发者
在Spring Boot中集成Swagger API文档
在Spring Boot中集成Swagger API文档
|
1月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
52 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
1月前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
68 1
|
2月前
|
前端开发 Java Spring
【非降版本解决】高版本Spring boot Swagger 报错解决方案
【非降版本解决】高版本Spring boot Swagger 报错解决方案
|
2月前
|
Java Spring
springboot 集成 swagger 2.x 和 3.0 以及 Failed to start bean ‘documentationPluginsBootstrapper‘问题的解决
本文介绍了如何在Spring Boot项目中集成Swagger 2.x和3.0版本,并提供了解决Swagger在Spring Boot中启动失败问题“Failed to start bean ‘documentationPluginsBootstrapper’; nested exception is java.lang.NullPointerEx”的方法,包括配置yml文件和Spring Boot版本的降级。
springboot 集成 swagger 2.x 和 3.0 以及 Failed to start bean ‘documentationPluginsBootstrapper‘问题的解决