nodejs express typescript 写的restapi怎么集成swagger

nodejs express typescript 写的restapi怎么集成swagger

为了在一个使用TypeScript编写的Node.js Express项目中集成Swagger文档,你可以遵循以下步骤:

  1. 安装所需的npm包: 首先,你需要安装swagger-ui-expressswagger-jsdoc这两个npm包。如果你还没有安装typescript, @types/node, express@types/express你也需要安装它们。
npm install express @types/express
npm install swagger-ui-express swagger-jsdoc
npm install typescript @types/node --save-dev
  1. 创建Swagger配置: 创建一个名为swagger.js或者swagger.ts的文件来定义Swagger的配置选项。通过JSDoc注释和Swagger规范来描述你的API。

例如,swagger.ts可能看起来像这样:

import swaggerJsDoc from 'swagger-jsdoc';

const swaggerOptions: swaggerJsDoc.Options = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'REST API Documentation',
      version: '1.0.0',
      description: 'This is a REST API documentation example',
    },
    servers: [
      {
        url: 'http://localhost:3000/', // 替换为你的实际服务器地址
      },
    ],
  },
  apis: ['./routes/*.ts'], // 指向你存放路由的文件夹,确保你的路由文件包含了Swagger的JSDoc注释
};

const swaggerDocs = swaggerJsDoc(swaggerOptions);
export default swaggerDocs;
  1. 在你的应用中设置Swagger中间件: 修改你的主应用文件(如app.ts)来设置并使用swagger-ui-express中间件,并将Swagger配置导入到中间件中。
import express, { Application } from 'express';
import swaggerUI from 'swagger-ui-express';
import swaggerDocs from './swagger';

const app: Application = express();

const PORT = process.env.PORT || 3000;

// 设置Swagger中间件
app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(swaggerDocs));

// 其他中间件和路由设置...

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
  1. 添加JSDoc注释: 在你的Express路由定义中添加Swagger JSDoc注释,以便swagger-jsdoc能够读取这些信息并生成API文档。

例如,一个简单的路由文件routes/users.ts可能包含以下内容:

import { Router } from 'express';

const router = Router();

/**
 * @swagger
 * /users:
 *   get:
 *     summary: Returns a list of users.
 *     responses:
 *       200:
 *         description: A JSON array of user objects.
 */
router.get('/users', (req, res) => {
  // 实现获取用户列表的逻辑...
  res.json([{ name: "John Doe" }]);
});

export default router;

完成上述步骤后,启动你的Express服务器,并在浏览器中访问http://localhost:3000/api-docs(端口号根据你的设置替换)。你就能看到生成的Swagger UI界面,其中展示了所有通过JSDoc注释定义的API端点。

请注意,你可能需要根据你自己的项目结构调整路径和配置。此外,如果你是在生产环境下工作,那么应该考虑只在开发或测试环境中启用Swagger UI。

如果/users 支持 page, size ,name 等参数,以及返回值例子,怎么写swagger

如果你的 /users 路由支持查询参数 page, size, 和 name,你可以在Swagger JSDoc注释中添加这些参数的定义,并且提供一个返回值示例。以下是一个更新后的路由文件routes/users.ts示例,其中包含了查询参数和返回值示例的Swagger注释:

import { Router } from 'express';

const router = Router();

/**
 * @swagger
 * components:
 *   schemas:
 *     User:
 *       type: object
 *       required:
 *         - id
 *         - name
 *       properties:
 *         id:
 *           type: string
 *           description: The auto-generated id of the user.
 *         name:
 *           type: string
 *           description: The name of the user.
 *       example:
 *         id: d290f1ee-6c54-4b01-90e6-d701748f0851
 *         name: John Doe
 *
 * /users:
 *   get:
 *     summary: Returns a list of users.
 *     parameters:
 *       - in: query
 *         name: page
 *         schema:
 *           type: integer
 *           default: 1
 *         description: Page number of the users listing
 *       - in: query
 *         name: size
 *         schema:
 *           type: integer
 *           default: 10
 *         description: Number of users per page
 *       - in: query
 *         name: name
 *         schema:
 *           type: string
 *         description: Filter by user's name
 *     responses:
 *       200:
 *         description: A JSON array of user objects.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 users:
 *                   type: array
 *                   items:
 *                     $ref: '#/components/schemas/User'
 *                 totalItems:
 *                   type: integer
 *                   description: Total number of users
 *                 totalPages:
 *                   type: integer
 *                   description: Total number of pages
 *                 currentPage:
 *                   type: integer
 *                   description: Current page number
 *               example:
 *                 users: [{ id: "d290f1ee-6c54-4b01-90e6-d701748f0851", name: "John Doe" }]
 *                 totalItems: 100
 *                 totalPages: 10
 *                 currentPage: 1
 */
router.get('/users', (req, res) => {
  // 实现获取用户列表的逻辑...
  const users = [
    { id: "d290f1ee-6c54-4b01-90e6-d701748f0851", name: "John Doe" },
    // 更多用户对象...
  ];
  const response = {
    users,
    totalItems: 100,
    totalPages: 10,
    currentPage: 1,
  };
  res.json(response);
});

export default router;

上面的注释定义了User模式,在/users路径中使用该模式,并且为page, size, 和 name查询参数提供了描述。它还定义了一个200 OK响应的结构和示例。当你运行你的应用并访问 Swagger UI 时,这些信息都会显示在你的API文档中。

确保你把JSDoc注释中的各个部分与你的实际代码、API行为和数据格式对齐。这包括正确的类型、描述、默认值以及任何可能的限制或验证规则。

这个需要写太多了,有没有简洁的,或者封装过的库

如果你觉得直接在代码中写大量的Swagger注释过于繁琐,可以考虑使用一些更加自动化的工具来简化这个过程。一个流行的选择是使用 tsoatsoa 是一个同时支持路由和Swagger/OpenAPI文档生成的TypeScript库,它能够根据装饰器(decorators)和TypeScript接口直接生成路由和Swagger定义。

要使用tsoa集成Swagger到你的Express应用,首先需要安装tsoa以及相关的依赖:

npm install tsoa express @types/express

然后,你可以按照以下步骤配置tsoa

  1. 创建控制器:使用tsoa提供的装饰器来定义你的控制器和方法。
import { Controller, Route, Get, Query } from 'tsoa';

@Route('users')
export class UsersController extends Controller {
  @Get()
  public async getUsers(
    @Query() page: number = 1,
    @Query() size: number = 10,
    @Query() name?: string
  ): Promise<User[]> {
    // 实现获取用户列表的逻辑...
    return [
      // ...返回用户数据
    ];
  }
}
  1. 添加tsoa配置:在项目的根目录下创建一个名为tsoa.json的配置文件,其中包含关于如何生成路由和Swagger文档的信息。
{
  "entryFile": "src/app.ts",
  "controllerPathGlobs": ["src/controllers/*Controller.ts"],
  "swagger": {
    "outputDirectory": "dist/swagger",
    "yaml": true,
    "specVersion": 3
  },
  "routes": {
    "routesDir": "src/routes"
  }
}
  1. 生成路由和Swagger文档:运行tsoa命令来自动生成路由和Swagger文档。
npx tsoa routes
npx tsoa spec
  1. 集成到Express应用中:使用生成的路由文件和Swagger文档集成到你的Express应用中。
import express, { Application } from 'express';
import swaggerUi from 'swagger-ui-express';
import * as swaggerDocument from './dist/swagger/swagger.json';

const app: Application = express();
const PORT = process.env.PORT || 3000;

const RegisterRoutes = require('./dist/routes').RegisterRoutes;
RegisterRoutes(app);

app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));

app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));

使用tsoa可以显著减少手动编写Swagger文档所需的工作量,并且保持TypeScript类型和API文档之间的一致性。但是,请注意,你可能需要根据自己的项目结构和需求对上述步骤做出调整。

用tsoa 对现在的express写的api改动太大了,有没有其他改动小的方式

如果您正在寻找一种改动较小的方式来为现有的Express API集成Swagger,并且希望减少手写注释的工作量,那么可以考虑使用swagger-autogen这个库。它能够自动生成Swagger文档,基于您当前的路由和附加的注释。

首先,安装swagger-autogen

npm install swagger-autogen

接着,创建一个新的脚本文件(例如 swagger.js),用于运行swagger-autogen

const swaggerAutogen = require('swagger-autogen')();

const doc = {
  info: {
    title: 'My API',
    description: 'API description',
  },
  host: 'localhost:3000',
  schemes: ['http'],
};

const outputFile = './path-to-output/swagger-output.json'; // Swagger文件生成的位置
const endpointsFiles = ['./path-to-your-routes/index.js']; // 你的路由文件的位置

// 运行swaggerAutogen
swaggerAutogen(outputFile, endpointsFiles, doc);

在您的路由或控制器中添加特定的注释,以便swagger-autogen能识别和生成文档。这些注释会比手写完整的Swagger规范简单很多。例如:

// users.js

// #swagger.start
/**
 * @route GET /users
 * @group Users - Operations about user
 * @param {integer} page.query.required - Page number
 * @param {integer} size.query.required - Number of users per page
 * @param {string} name.query - Filter by user's name
 * @returns {object} 200 - An array of user info
 * @returns {Error}  default - Unexpected error
 */
router.get('/users', (req, res) => {
  // ...
});
// #swagger.end

在添加了所需的注释后,您只需要运行一次创建的swagger.js脚本文件即可生成Swagger文档文件。最后,在您的Express应用中引入并使用swagger-ui-express来展示Swagger UI。

const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./path-to-output/swagger-output.json');

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));

然后,当你重启你的Express应用程序时,可以通过访问/api-docs端点查看Swagger UI。

使用swagger-autogen,您可以在现有代码基础上进行较小的改动,通过简单的注释来自动生成Swagger文档,而不需要重构整个API或大量编写Swagger规范。

我的项目是typescript写的上面 swagger-autogen创建脚本怎么写

当使用TypeScript时,swagger-autogen的脚本设置会略有不同,因为你需要适应TypeScript语法和模块系统。以下是一个用TypeScript编写的swagger-autogen脚本示例:

首先安装swagger-autogen(如果你还没有安装):

npm install swagger-autogen --save-dev

然后在你的项目中创建一个新的TypeScript文件,比如叫做swagger.ts:

// 引入类型定义,以便正确使用swaggerAutogen
import swaggerAutogen from 'swagger-autogen';

const doc = {
  info: {
    title: 'My API',
    description: 'API Documentation',
  },
  host: 'localhost:3000',
  schemes: ['http'],
};

const outputFile = './swagger-output.json'; // Swagger文件生成的位置
const endpointsFiles = ['./src/routes.ts']; // 你的路由文件的位置

// 初始化swaggerAutogen并运行它
const swaggerAutoGen = swaggerAutogen();

swaggerAutoGen(outputFile, endpointsFiles, doc).then(async () => {
  await import('./src/server'); // 你的主服务器文件
});

请确保修改endpointsFiles数组中的路径,以便指向你实际存放Express路由的文件。

在你的路由和控制器代码中添加必要的注释,swagger-autogen将会识别这些注释并生成相应的Swagger规范。例如:

// routes.ts

import express from 'express';

const router = express.Router();

/* 
  #swagger.description = 'Endpoint to retrieve users'
  #swagger.parameters['page'] = { description: 'Page number', type: 'integer' }
  #swagger.parameters['size'] = { description: 'Number of users per page', type: 'integer' }
  #swagger.parameters['name'] = { description: "User's name for filtering", type: 'string' } 
*/
router.get('/users', (req, res) => {
  // Your code here...
});

export default router;

最后,在package.json中添加一个新的脚本来运行swagger-autogen:

"scripts": {
  "swagger": "ts-node ./swagger.ts"
}

你可能需要ts-node和相关的类型定义来执行TypeScript文件:

npm install ts-node @types/node --save-dev

现在,通过运行下面的命令来生成Swagger文档:

npm run swagger

记得在你的Express应用中引入并使用swagger-ui-express来提供Swagger UI:

// server.ts 或 app.ts

import express from 'express';
import swaggerUi from 'swagger-ui-express';
import * as swaggerDocument from './swagger-output.json';

const app = express();

// 使用刚刚生成的Swagger文档设置Swagger UI
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));

// ...其他的Express配置和路由

export default app;

运行你的Express应用,并访问/api-docs端点查看API的Swagger文档。

/* #swagger.description = 'Endpoint to retrieve users' #swagger.parameters['page'] = { description: 'Page number', type: 'integer' } #swagger.parameters['size'] = { description: 'Number of users per page', type: 'integer' } #swagger.parameters['name'] = { description: "User's name for filtering", type: 'string' } */ 怎么表示 一个字段是必选还是可以选,字段值例子,字段类型可以是string或integer等

swagger-autogen中,你可以通过添加requiredexample属性来指定参数是否是必须的以及提供一个字段值的例子。如果你想要表示一个字段可能有多种类型,你可以使用type属性并将其设置为一个包含所有可能类型的数组。

以下是一个具体的示例:

// routes.ts

import express from 'express';

const router = express.Router();

/* 
  #swagger.description = 'Endpoint to retrieve users'
  #swagger.parameters['page'] = {
    in: 'query',
    description: 'Page number of the user listing',
    required: true, // 设置参数为必选
    type: 'integer',
    example: 1, // 提供一个字段值的例子
  }
  #swagger.parameters['size'] = {
    in: 'query',
    description: 'Number of users per page',
    type: 'integer',
    example: 10,
  }
  #swagger.parameters['name'] = {
    in: 'query',
    description: "User's name for filtering",
    type: 'string',
    required: false, // 这个参数是可选的
    example: 'John Doe', // 提供一个字段值的例子
  } 
*/
router.get('/users', (req, res) => {
  // Your code here...
});

export default router;

在这个例子中,page 参数被标记为 required: true 表示它是必选的,而 name 参数则是可选的,因为它被标记为 required: false。每个参数还包括了类型信息和一个实际的例子。

如果你希望一个字段可以接受多种类型(尽管这在实际API设计中不太常见),你可以像下面这样指定类型数组:

#swagger.parameters['mixedTypeParam'] = {
  in: 'query',
  description: 'A parameter that can be either a string or an integer',
  type: ['integer', 'string'], // 指定多种可能的类型
  example: '42', // 提供一个示例值
}

请注意,在OpenAPI (Swagger) 规范中,通常建议对于查询参数保持单一类型,以便更清晰地说明API的期望行为。如果你需要支持多种类型,可能要考虑将其分成两个不同的参数或者在文档中特别说明这种灵活性。

in: 'query', 什么意思

在Swagger文档中,in 字段用于指定参数的位置。对于HTTP请求,参数可以位于不同的位置,这些位置对应于不同的传递方式。in 字段告诉Swagger(以及使用该API的开发者)这个参数应该在何处找到。

in: 'query' 表示参数是一个查询参数(query parameter),即它应该作为URL的一部分被传递,位于问号?之后,并且可以通过键值对的形式串联起来。这样的参数通常用于过滤结果、排序或者是进行分页等。

例如,一个典型的带有查询参数的URL可能会像这样:

https://example.com/api/users?page=2&size=10&name=John

在这个例子中,page, size, 和 name 是查询参数。

Swagger/OpenAPI支持多种in字段值,表示参数可以出现在不同的位置:

  • query: 参数位于URL的查询字符串中。
  • header: 参数应该作为HTTP请求头的一部分发送。
  • path: 参数是URL路径的一部分,通常用来指定资源ID。
  • cookie: 参数在cookie中传送。
  • body: (仅OpenAPI 2.0 或 Swagger 2.0 中使用)参数作为请求体的一部分传递。
  • formData: (仅OpenAPI 2.0 或 Swagger 2.0 中使用)参数作为表单数据提交,通常用于文件上传。

如果你正在编写一个Swagger注释,你需要根据实际情况选择正确的in值,确保API的使用者能够知道如何正确地传递参数。

/* #swagger.description = "Update user's information" #swagger.parameters['name'] = {in: 'body', description: 'user name', type: 'string', required: true} #swagger.parameters['contactInformation'] = {in: 'body', description: "user's contracts", type: 'json string' } #swagger.parameters['description'] = {in: 'body', description: "user's description", type: 'string' } #swagger.parameters['avatar'] = {in: 'fromData', description: "user's avatar", type: 'file' } / / #swagger.description = "Update user's information" #swagger.parameters['name'] = {in: 'body', description: 'user name', type: 'string', required: true} #swagger.parameters['contactInformation'] = {in: 'body', description: "user's contracts", type: 'json string' } #swagger.parameters['description'] = {in: 'body', description: "user's description", type: 'string' } #swagger.parameters['avatar'] = {in: 'fromData', description: "user's avatar", type: 'file' } */ router.post('/update', async (req: any, res) 这个api同时支持body和文件上传,这样写swagger注释,我生成后avatar这个文件上传的没有出来

Swagger中对于同时接收body参数和文件上传(通常是multipart/form-data)的处理稍有不同。在 OpenAPI(Swagger)3.0 规范中,你需要使用requestBody来描述发送到API的整个请求内容。

当你有一个接口既接受JSON payload也接受文件时,你应该将其定义为multipart/form-data,然后在content里面分别描述每个字段。下面是一个如何在swagger-autogen注释中构造这种情况的例子:

// src/routers/user.ts

/* 
  #swagger.description = "Update user's information"
  #swagger.consumes = ['multipart/form-data']
  #swagger.parameters['obj'] = {
    in: 'body',
    description: 'User details',
    required: true,
    schema: {
      $name: { type: 'string', description: 'user name', required: true },
      $contactInformation: { type: 'string', description: "user's contracts (as JSON string)" },
      $description: { type: 'string', description: "user's description" },
      // 注意:不需要为文件字段提供类型
    }
  }
*/
router.post('/update', async (req, res) => {
  // Your code here...
});

注意几点:

  • 因为在一个multipart/form-data请求中所有部分都包含在请求体中,所以你不再单独指定每个in: 'body' 参数。相反,你需要创建一个名为obj(或任何其他名字)的虚拟参数,用来表示整个请求体。
  • schema对象中,字段名称前面要加上$符号,这是swagger-autogen用来识别JSON结构中的属性的方式。
  • 对于文件字段,不需要在schema中说明,因为它们会被自动检测并处理(只需要在表单中正确地设置type='file')。

此外,请注意你的注释中有一个小错误:in: 'fromData' 应该是 in: 'formData'。但是在上面的例子中,我们已经去掉了单独的avatar字段,因为它会作为文件随表单一起发送,并且由swagger-autogen自动检测。

如果swagger-autogen没有正确生成对于文件上传的部分,你可以尝试更新库到最新版本,因为较老版本可能不支持某些特性。如果问题仍然存在,可以考虑直接编辑生成的Swagger JSON文件,或者使用其他工具来手动编写API文档。