使用node+typescript搭建mvc后台(四)--使用swagger配置接口文档

1,093 阅读3分钟

使用swagger配置接口文档

添加swaggerloader

import basicAuth from 'express-basic-auth';
import { MicroframeworkLoader, MicroframeworkSettings } from 'microframework-w3tec';
import * as path from 'path';
import * as swaggerUi from 'swagger-ui-express';
import * as express from 'express';
import { env } from '../env';

export const swaggerLoader: MicroframeworkLoader = (settings: MicroframeworkSettings | undefined) => {
    if (settings && env.swagger.enabled) {
        const expressApp = settings.getData('express_app');
        // 获取swagger配置 文件
        const swaggerFile = require(path.join(__dirname, '..', env.swagger.file));

        // 获取swagger基本信息
        swaggerFile.info = {
            title: env.app.name,
            description: env.app.description,
            version: env.app.version,
        };
        // 配置swagger服务请求路径
        swaggerFile.servers = [
            {
                url: `${env.app.schema}://${env.app.host}:${env.app.port}${env.app.routePrefix}`,
            },
        ];
        // 创建swagger服务。
        expressApp.use(
            env.swagger.route, // 配置swagger路由
            env.swagger.username ? basicAuth({
                users: {
                    [`${env.swagger.username}`]: env.swagger.password,
                },
                challenge: true,
            }) : (req:express.Request, res:express.Response, next:express.NextFunction) => next(),
            swaggerUi.serve,
            swaggerUi.setup(swaggerFile)
        );

    }
};

swaggerloader需要配置在expressloader实例之后。因为swagger需要拿到express的实例进行使用。所以在这之前我们也需要把express里把实例存到全局的setting中。

··········· 
const debug = iDebug('node-mvc:server');
    const port = normalizePort(process.env.PORT || '3000');
    app.set('port', port);
    settings?.setData('express_app',app);

    const server = http.createServer(app);

    server.listen(port);
    // server.on('error', onError);
    server.on('listening', onListening);
···········

这里一个比较值得注意的地方就是使用的use里有一个basicAuth方法,这里是调用了express-basic-auth,限制了swagger页面的访问权限。毕竟这种接口文档也不能给所有人看到的嘛。而use的第一个参数是路径。其他后面可以接多个function。只有前面的一个function使用了next才会进入下一个function。这大概是这部分原理的实现。

swagger.json

接着来看看swagger.json的配置。

{
    "swagger": "2.0", // swagger文版本
    "info": {
        "description": "node-mvc", // 描述
        "version": "1.0.0", // 版本号
        "title": "node-mvc", // 标题
        "contact": {
            "email": "xxxxxxxxxxxm@163.com" // 联系邮箱
        }
    },
    "host": "localhost:3000", // 配置服务路径
    "basePath": "/api", // 根路径
    "tags": [ // 标签
        {
            "name": "User",
            "description": "关于用户类的操作"
        }
    ],
    "schemes": [ // 请求协议
        "http"
    ],
    "paths": { // 路径
        "/user": {
            "post": { // restful methods
                "tags": [
                    "User" // 对应的标签
                ],
                "summary": "新建用户", // 概括
                "description": "添加一个用户", // 描述
                "operationId": "createUser", // 操作id,会对应hash值
                "produces": [
                    "application/json" // 返回格式
                ],
                "parameters": [ // 参数
                    {
                        "in": "body",
                        "name": "body",
                        "description": "创建一个用户对象",
                        "required": true,
                        "schema": {
                            "$ref": "#/definitions/User"
                        }
                    }
                ],
                "responses": { // 返回内容
                    "default": {
                        "description": "successful operation"
                    }
                }
            },
            "get": {
                "tags": [
                    "User"
                ],
                "summary": "获取用户列表",
                "description": "获取用户列表",
                "operationId": "getUserList",
                "produces": [
                    "application/json"
                ],
                "responses": {
                    "default": {
                        "description": "successful operation"
                    }
                }
            }
        },
        "/user/{id}": {
            "delete": {
                "tags": [
                    "User"
                ],
                "summary": "删除单个用户",
                "description": "根据用户id删除用户",
                "operationId": "removeUserById",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "用户id",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "ok",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "code": {
                                            "type": "number"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "$ref": "#/definitions/User"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "put": {
                "tags": [
                    "User"
                ],
                "summary": "修改单个用户",
                "description": "根据用户id修改用户",
                "operationId": "updateUserById",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "用户id",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "in": "body",
                        "name": "body",
                        "description": "创建一个用户对象",
                        "required": true,
                        "schema": {
                            "$ref": "#/definitions/User"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "ok",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "code": {
                                            "type": "number"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "$ref": "#/definitions/User"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "get": {
                "tags": [
                    "User"
                ],
                "summary": "获取单个用户",
                "description": "根据用户id获取用户",
                "operationId": "getUserById",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "用户id",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "ok",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "code": {
                                            "type": "number"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "$ref": "#/definitions/User"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "securityDefinitions": { // 安全校验配置
        "api_key": {
            "type": "apiKey",
            "name": "authorization",
            "in": "header"
        }
    },
    "definitions": { // 定义model
        "User": {
            "type": "object",
            "properties": {
                "id": {
                    "type": "integer",
                    "format": "int64",
                    "description": "用户id"
                },
                "wx_name": {
                    "type": "string",
                    "description": "微信名"
                },
                "avatar": {
                    "type": "string",
                    "description": "头像地址"
                },
                "name": {
                    "type": "string",
                    "description": "自定义名称"
                },
                "role": {
                    "type": "string",
                    "description": "角色"
                },
                "init": {
                    "type": "string",
                    "description": "是否初始化"
                }
            }
        }
    },
    "externalDocs": {
        "description": "Find out more about Swagger",
        "url": "http://swagger.io"
    }
}

注意。这里的swagger要规定好2.0版本。不同版本有不同版本的配置方法。也可以配置为openapi": "3.0.0"

petstore.swagger.io/v2/swagger.…这里附一份官网的详细配置

修改controller配置

import { Get, JsonController, Post, Body, OnUndefined, Param, Delete, Put } from "routing-controllers";
import { UserService } from '../services/UserService';
import { User } from "../models/User";
import AjaxResponse from "../commonClass/AjaxResponse";

@JsonController('/user')
export default class UserController {
    constructor(
        private userService: UserService
    ) {
    }

    @Get()
    public find(): Promise<AjaxResponse>  {
        return this.userService.find();
    }

    @Post()
    public create(@Body() user: User): Promise<AjaxResponse> {
        return this.userService.create(user);
    }

    @Put('/:id')
    public update(@Body() user: User,@Param('id') id: string): Promise<AjaxResponse> {
        return this.userService.update(id,user);
    }

    @Get('/:id')
    public one(@Param('id') id: string): Promise<AjaxResponse> {
        return this.userService.findOne(id);
    }

    @Delete('/:id')
    public delete(@Param('id') id: string): Promise<AjaxResponse> {
        return this.userService.delete(id);
    }

}

这里我们添加了一个AjaxResponse作为统一的返回对象。

export default class AjaxResponse{
    public status:number; // 0-成功 1-失败
    public message:string|undefined; // 返回的内容
    public data:string;
    constructor(status:number,message?:string,data?:any)
    {
        this.status = status;
        this.message = message;
        this.data = data;
    }
}

同样的。既然修改了返回参数。那么service类就也要随之更改

import { Service } from 'typedi';
import { OrmRepository } from 'typeorm-typedi-extensions';
import uuid from 'uuid';

import { User } from '../models/User';
import { UserRepository } from '../repositories/UserRepository';
import AjaxResponse from '../common_class/AjaxResponse';

@Service()
export class UserService {

    constructor(
        @OrmRepository() private userRepository: UserRepository,
    ) { }

    public async find(): Promise<AjaxResponse> {
        const list =  await this.userRepository.find();
        return new AjaxResponse(1,'获取成功',list);
    }

    public async findOne(id: string): Promise<AjaxResponse> {
        const user = await this.userRepository.findOne({ id });
        return new AjaxResponse(1,'获取成功',user);
    }

    public async create(user: User): Promise<AjaxResponse> {
        user.id = uuid.v1();
        const newUser = await this.userRepository.save(user);
        return new AjaxResponse(1,'新增成功',user);
    }

    public async update(id: string, user: User): Promise<AjaxResponse> {
        user.id = id;
        const updateUser = await this.userRepository.save(user);
        return new AjaxResponse(1,'修改成功',updateUser);
    }

    public async delete(id: string): Promise<AjaxResponse> {
        const result =  await this.userRepository.delete(id);
        return new AjaxResponse(1,'删除成功');
    }

}

修改启动命令

这些模块都搭建好之后要记得把启动命令修改一下,因为之前都只是监听ts文件的改变,并没有监听json文件。所以要加上json文件的配置。

    "dev": "export NODE_ENV=development&&nodemon --watch 'src/' -e ts,json --exec 'ts-node' ./src/app.ts"

主要也就是使用逗号隔开。

启动

最后再启动服务。浏览器输入http://localhost:3000/swagger/#/就可以看到swagger文档了

image.png


仓库代码