我使用过Markdown,Wiki管理接口文档,过程实在难以称得上美好,工作量巨大并且十分无趣。接口的变更需要维护相关文档;接口无法方便地进行调试、测试;以及接口的管理完全依赖于人。这些问题不仅导致接口文档难以维持很高的质量,而且还会让开发人员花费更多的时间在接口调试上,甚至影响项目进度。最最最重要的是,这可能会影响到我们的心情,这可是无法忍受的事情 : (
于是乎我便四处寻求解决方案,功夫不负有心人。我发现了OpenAPI Specification,并且OpenAPI协议生态圈也很完善。Swagger 包含了很多工具链,Swagger UI可以自动根据协议文件生成接口文档。而OpenAPI中的数据类型和数据模型是基于JSON-Schema Draft 4。
希望此库可以帮到有同样需求的你,happy coding。
哦,对了,PR & Issue & Star are welcome! : )
- 内置Swagger-UI,方便查看、调试接口
- 支持OpenAPI/Swagger2.0规范,支持json、yaml格式
- 支持�更友好、方便的API文档切分方案
- 支持自定义插件(中间件加载、表单校验、响应处理、错误处理等将以插件形式提供)
- 继承自Koa-Router,保持原功能、特性,性能。
如果你不是1.x的用户,请直接跳过本部分内容。 如果你是1.x的用户并且想升级到2.0版本,很抱歉你将无法傻瓜式的升级到2.0版本,请仔细阅读本部分的内容Migration并且按照操作手册升级。
# required koa 2.x
> npm install koa-oai-router --save
下面将带你学习如何使用router构建一个良好组织结构和配备接口文档的Web Server。 本例中基本涉及了router的所有重点内容,包括:
- 配置router
- 配置插件
- 挂载插件到router
- 挂载router到app
- 编写接口描述文档
- 使用插件
- 使用api-explorer
我们的目标是:
- 创建一个REST API Server
- 编写一个pets查询接口,并返回查询到的pets数组
- 编写一个pets新建接口,并返回pet和id
- 生成接口文档,体验api-explorer
下面我们就正式开始喽。
// ./app.js
const Koa = require('koa');
const logger = require('koa-logger');
const bodyParser = require('koa-bodyparser');
const Router = require('koa-oai-router');
const middleware = require('koa-oai-router-middleware');
const app = new Koa();
// *配置router - 从api目录下加载接口描述并生成api文档
const router = new Router({
apiDoc: './api',
});
// *配置插件 - 识别api文档中的x-oai-middleware并从controllers中加载相应的中间件
// *挂载插件到router
router.mount(middleware, './controllers');
app.use(logger());
app.use(bodyParser());
// *挂载router到app
app.use(router.routes());
app.listen(3000);
创建业务中间件目录controllers
并编写业务中间件。
// ./controllers/pets.js
const database = [];
// 根据tags查询数据库中的pets,并根据limit限制查询结果。
async function get(ctx, next) {
const { tags = '', limit = 999 } = ctx.request.query;
const tagsArray = tags.split(',');
const docs = [];
database.forEach((item, idx) => {
if (tagsArray.indexOf(item.tag) !== -1 && docs.length < limit) {
item.id = idx + 1;
docs.push(item);
}
});
ctx.response.body = docs;
}
// 新建一个pet存储到数据库中。
async function post(ctx, next) {
const body = ctx.request.body;
database.push(body);
ctx.response.body = {
id: database.length,
name: body.name,
tag: body.tag,
};
}
module.exports = {
get,
post,
};
在这里你可以对服务的基础信息进行描述,如服务的版本,�基础路径,传输协议,作者,许可协议等。
# ./api/api.yaml
swagger: '2.0'
info:
version: 1.0.0
title: Swagger Petstore
description: >-
A sample API that uses a petstore as an example to demonstrate features in
the swagger-2.0 specification
termsOfService: 'http://swagger.io/terms/'
contact:
name: Swagger API Team
license:
name: MIT
basePath: /api
schemes:
- http
consumes:
- application/json
produces:
- application/json
编写api接口描述信息,这里的path是一个相对路径。path会追加在basePath的后面组成一个完成的URL,其他字段描述了接口的详细信息。详情请参考Paths。
# ./api/paths/pets.yaml
/pets:
get:
description: "Returns all pets from the system that the user has access to"
operationId: "findPets"
produces:
- "application/json"
tags:
- pets
x-oai-middleware:
- file: pets
handler: get
parameters:
- name: "tags"
in: "query"
description: "tags to filter by"
required: false
type: "array"
items:
type: "string"
collectionFormat: "csv"
- name: "limit"
in: "query"
description: "maximum number of results to return"
required: false
type: "integer"
format: "int32"
responses:
"200":
description: "pet response"
schema:
type: "array"
items:
$ref: "#/definitions/Pet"
default:
description: "unexpected error"
schema:
$ref: "#/definitions/ErrorModel"
post:
description: "Creates a new pet in the store. Duplicates are allowed"
operationId: "addPet"
produces:
- "application/json"
tags:
- pets
x-oai-middleware:
- file: pets
handler: post
parameters:
- name: "pet"
in: "body"
description: "Pet to add to the store"
required: true
schema:
$ref: "#/definitions/NewPet"
responses:
"200":
description: "pet response"
schema:
$ref: "#/definitions/Pet"
default:
description: "unexpected error"
schema:
$ref: "#/definitions/ErrorModel"
你可以通过definitions定义一些常用的数据模型,这些模型可以很方便地复用在请求参数或者响应结果的定义中,减少文档的“坏味道”。这些数据模型可以是基础数据类型、数组、复杂的JSON对象,详情请参考Definitions。
1.定义接口错误响应数据模型ErrorModel。
# ./api/definitions/error.yaml
ErrorModel:
type: "object"
required:
- "code"
- "message"
properties:
code:
type: "integer"
format: "int32"
message:
type: "string"
2.定义查询成功响应数据模型Pet,定义新增请求数据模型NewPet。
# ./api/definitions/pets.yaml
Pet:
type: "object"
allOf:
- $ref: "#/definitions/NewPet"
- required:
- "id"
properties:
id:
type: "integer"
format: "int64"
NewPet:
type: "object"
required:
- "name"
properties:
name:
type: "string"
tag:
type: "string"
启动WEB服务,测试接口,体验api-explorer。
> node app.js
>
> curl -X POST "http://localhost:3000/api/pets" -H "Content-Type: application/json" -d "{ \"name\": \"luck\", \"tag\": \"dog\"}"
> {"id":1,"name":"luck","tag":"dog"}
>
> curl -X POST "http://localhost:3000/api/pets" -H "Content-Type: application/json" -d "{ \"name\": \"lily\", \"tag\": \"cat\"}"
> {"id":2,"name":"lily","tag":"cat"}
>
> curl -X POST "http://localhost:3000/api/pets" -H "Content-Type: application/json" -d "{ \"name\": \"mike\", \"tag\": \"dog\"}"
> {"id":3,"name":"mike","tag":"dog"}
>
> curl -X GET "http://localhost:3000/api/pets?tags=cat,dog&limit=2"
> [{"name":"luck","tag":"dog","id":1},{"name":"lily","tag":"cat","id":2}]
可以看到,我们编写的业务中间件都已经被正常调用了。 使用浏览器打开**http://localhost:3000/api-explorer**,现在你可以体验api-explorer了。
名称 | 描述 | 状态 |
---|---|---|
koa-oai-router-middleware | 业务中间件加载 | 完成 |
koa-oai-router-correction | 请求表单预处理 | 完成 |
koa-oai-router-parameters | 请求表单校验 | 完成 |
koa-oai-router-responses | 请求结果处理 | 完成 |
koa-oai-router-cache | 请求缓存插件 | 完成 |
koa-oai-router-rbac | 请求权限控制 | 计划中 |
koa-oai-router-controller-mongo | MongoDB REST server | 开发中 |
- 支持OpenAPI 3.x规范
- 更多的插件
- 更多的单元测试
- Benchmark