diff --git a/README.md b/README.md index 71f4a48..f97b88b 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,6 @@ [![Downloads][downloads-image]][downloads-url] [![Dependency Status][david-img]][david-url] -[![NPM](https://nodei.co/npm/koa-oai-router.png?downloads=true&stars=true)](https://nodei.co/npm/koa-oai-router/) - [travis-img]: https://travis-ci.org/BiteBit/koa-oai-router.svg?branch=master [travis-url]: https://travis-ci.org/BiteBit/koa-oai-router [coveralls-img]: https://coveralls.io/repos/github/BiteBit/koa-oai-router/badge.svg?branch=master @@ -24,735 +22,357 @@ [license-url]: http://opensource.org/licenses/MIT [node-image]: https://img.shields.io/badge/node.js-v4.0.0-blue.svg [node-url]: http://nodejs.org/download/ +[koa-router]: https://github.com/alexmingoia/koa-router +[oai]: https://github.com/OAI/OpenAPI-Specification +[swagger]: http://swagger.io +[swagger-ui]: http://swagger.io/swagger-ui +[jsonschema]: http://json-schema.org +[oai-paths]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#pathsObject +[oai-definitions]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#definitionsObject +[oai-router-middleware]: https://github.com/oaijs/koa-oai-router-middleware +[oai-router-parameters]: https://github.com/oaijs/koa-oai-router-parameters +[oai-router-responses]: https://github.com/oaijs/koa-oai-router-responses +[oai-router-correction]: https://github.com/oaijs/koa-oai-router-correction +[oai-router-cache]: https://github.com/oaijs/koa-oai-router-cache +[oai-router-rbac]: https://github.com/oaijs/koa-oai-router-rbac +[oai-router-examples]: https://github.com/oaijs/koa-oai-router-examples +[migration]: ./docs/en/migration.md +[usage-guides]: ./docs/en/usage-guides.md +[references]: ./docs/en/references.md +[api-explorer-img]: ./docs/api-explorer.png?raw=true [中文](./README.zh-CN.md) [English](./README.md) -I have used markdown and wiki to manage api doc, from which I have suffered a lot. It wastes too much time and is very boring. The docuement should be repaired when you change the api. It's very unconvenient to test and debug. The management of api doc totally depends on people. As a result, it is hard to make docuement have high quality. Meanwhile, the developers will spend more time on testing, which may have a bad effect on project. What's worse, it will affect our mood, which is unbearable for me : (. +I have used markdown and wiki to manage api doc, from which I have suffered a lot. It wastes too much time and is very boring. The docuement should be repaired when you change the api. It's very unconvenient to test and debug. The management of api doc totally depends on people. As a result, it is hard to make docuement have high quality. Meanwhile, the developers will spend more time on testing, which may have a bad effect on project. What's worse, it will affect our mood, which is unbearable for me : ( -So I try my best to solve this problem. When there is a will, there is a way. Finally, I find The OpenAPI Specification. And it's ecological circle is perfect. Swagger includes lots of tool chain. According to the Specification, Swagger UI can produce the docuement. The data types and models of OpenAPI are based on the JSON-Schema Draft 4. +So I try my best to solve this problem. When there is a will, there is a way. Finally, I find The [OpenAPI Specification][oai]. And it's ecological circle is perfect. [Swagger][swagger] includes lots of tool chain. According to the Specification, [Swagger UI][swagger-ui] can produce the docuement. The data types and models of OpenAPI are based on the [JSON-Schema Draft 4][jsonschema]. I truly hope that this library can help those who are in the same trouble. Happy coding. -*BTW,PR & Issue & Star are welcome! : )* +BTW,PR & Issue & Star are welcome! : ) --- -- [Koa-OAI-Router](#koa-oai-router) -- [Features](#features) -- [Installation](#installation) -- [Quick Start](#quick-start) - - [Creating API doc](#creating-api-doc) - - [Creating controller](#creating-controller) - - [Creating koa app](#creating-koa-app) - - [Using api-explorer](#using-api-explorer) -- [Advanced](#advanced) - - [Router](#router) - - [apiDoc](#apidoc) - - [controllerDir](#controllerdir) - - [port](#port) - - [server](#server) - - [validator](#validator) - - [versioning](#versioning) - - [apiExplorerVisible](#apiexplorervisible) - - [apiExplorerPath](#apiexplorerpath) - - [apiExplorerStaticPath](#apiexplorerstaticpath) - - [jsonSchemaFormatters](#jsonschemaformatters) - - [errorHandler](#errorhandler) - - [defaultResponseSchemas](#defaultresponseschemas) - - [Router.routes()](#routerroutes) - - [Router.apiExplorer()](#routerapiexplorer) - - [Router.apiExplorerV3()](#routerapiexplorerv3) - - [Router.use(keyword, fn)](#routerusekeyword-fn) - - [Router.extend(endpoint, fn)](#routerextendendpoint-fn) - - [Contrller](#contrller) - - [file](#file) - - [handler](#handler) - - [Parameter validate](#parameter-validate) - - [header](#header) - - [path](#path) - - [query(formData)](#queryformdata) - - [body](#body) - - [Response validate(incomplete)](#response-validateincomplete) - - [Error handle](#error-handle) -- [Plan](#plan) + + + +* [Koa-OAI-Router](#koa-oai-router) +* [Features](#features) +* [Migration](#migration) +* [Installation](#installation) +* [Getting Started](#getting-started) + * [Creating web server](#creating-web-server) + * [Creating business middleware](#creating-business-middleware) + * [Creating api doc](#creating-api-doc) + * [Writing api base info](#writing-api-base-info) + * [Writing `paths` info](#writing-paths-info) + * [Writing `definitions` info](#writing-definitions-info) + * [Enjoying api-explorer](#enjoying-api-explorer) +* [Documentation](#documentation) +* [Ecosystem](#ecosystem) +* [Plan](#plan) + + --- # Features -* Built-in Swagger-UI, easy view and debug -* Auto generate route by OpenAPI/Swagger api doc, and validate parameters -* Support OpenAPI/Swagger2.0 Specification with yaml or json file -* Support Json Schema v4, validate query,body,path,header -* Support custom Json Schema format -* Support custom error handler - -# Installation - -> For koa@>=2.x (next): - -```bash -npm install koa-oai-router@next --save -``` - -> For koa@<2.x: - -**Not Support Yet!** +* Built-in Swagger-UI, easy to view and debug +* Support OpenAPI/Swagger2.0 specification with yaml or json file +* More friendly and convenient api doc splitting solution +* Plugin system. Middleware loader, form validator, response handler, error handler supported as plugin +* Inherit from [Koa-Router][koa-router], maintain the original function, features and performance -# Quick Start - -## Creating API doc -If you not know how to do this. please read [OpenAPI](https://github.com/OAI/OpenAPI-Specification) first. - -```yaml -# api/api.yaml +# Migration +If you are not a 1.x user, please skip this section directly. +If you are a 1.x user and want to upgrade to version 2.0, I'm sorry that you will not upgrade to version 2.0 easily. Please read this [Migration][migration] carefully and follow the operation manual to upgrade. -swagger: '2.0' -info: - version: 1.0.0 - title: koa-oai-router -consumes: - - application/json -produces: - - application/json -basePath: /api -paths: - /people: - get: - tags: - - People - description: find a people by name or mobile - x-oai-controller: - - file: people - handler: get - parameters: - - name: name - in: query - type: string - - name: mobile - in: query - type: string - responses: - 200: - description: people's info - schema: - $ref: '#/definitions/People' - default: - description: unexpected error - schema: - $ref: '#/definitions/Error' - post: - tags: - - People - description: input a people's info - x-oai-controller: - - file: people - handler: post - parameters: - - name: body - in: body - required: true - schema: - $ref: '#/definitions/People' - responses: - 200: - description: people's info - schema: - $ref: '#/definitions/People' - default: - description: unexpected error - schema: - $ref: '#/definitions/Error' -definitions: - People: - type: object - required: - - name - - sex - - height - - weight - properties: - name: - type: string - sex: - type: string - enum: - - male - - female - height: - type: integer - format: int32 - minimum: 10 - maximum: 1000 - weight: - type: number - format: float - minimum: 50 - maximum: 200 - mobile: - type: string - Error: - title: Error - type: object - required: - - status - - error - properties: - status: - type: integer - path: - type: string - error: - type: string - detail: - type: object +# Installation +```sh +# required koa 2.x +> npm install koa-oai-router --save ``` -## Creating controller - -do your staff code - -```javascript -// controllers/people.js - -var people = {name: 'BiteBit'}; - -function get(ctx, next) { - ctx.body = people; -} +# Getting Started +The following will teach you how to use the router to build a web server with a good organizational structure and `api-explorer`. -function post(ctx, next) { - people = ctx.request.body; - ctx.body = people; -} +In this case, it basically covers all the key points of the router, including: +* configure router +* configure plugin +* mount plugin to router +* mount router to app +* write api doc +* use plugin +* enjoy api-explorer -module.exports = { - get: get, - post: post -}; -``` +our target is: +* to create a REST API Server +* to implement a pets query api and return the array of pets found +* to implement a creating api for pets and return the pet and id +* to generate api documentation and enjoy api-explorer -## Creating koa app +Here we go. +## Creating web server ```javascript -// app.js +// ./app.js -import Koa from ('koa'); -import bodyParser from ('koa-bodyparser'); -import Router from ('koa-oai-router'); +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(); -const server = app.listen(9000); -app.use(bodyParser()); +// *configure router - load api doc from directory api +const router = new Router({ + apiDoc: './api', +}); -// set koa-oai-router options -var opt = { - // path of api doc - apiDoc: './api/api.yaml', - // dir of controllers - controllerDir: './controllers', - // get listening port from server - server: server, - // add major version to api prefix - versioning: true, - // show api-explorer - apiExplorerVisible: true -}; +// *configure plugin - identify x-oai-middleware in the api file and load the appropriate middleware from controllers +// *mount plugin to router +router.mount(middleware('./controllers')); -var router = new Router(opt); -// mount routes in api doc +app.use(logger()); +app.use(bodyParser()); +// *mount router to app app.use(router.routes()); -// mount api-explorer -app.use(router.apiExplorer()); -``` - -## Using api-explorer - -open http://127.0.0.1:9000/api-explorer with browser,enjoy it! - -![Api Explorer](./images/api-explorer.png?raw=true) - -# Advanced - -## Router - -### apiDoc - -string required - -Api doc's path, support OpenAPI2.0 json,yaml. - -### controllerDir - -string required -Dir of controllers, it's used when set **file and handler** of a api. - -### port - -number optional default 80 - -The port is koa server listening, used to be log out api-explorer url. - -### server - -net.Socket optional - -The Socket is koa serving, which will find serving **port** automatically. No need to set *port* and *server* together. - -### validator - -string optional default is *ajv* - -You can choice [ajv](https://github.com/epoberezkin/ajv), [tv4](https://github.com/geraintluff/tv4) or *null*. **I'm still finding a perfect Json Schema validator**. - -* ajv Best performance in [Benchmark ](https://github.com/ebdrup/json-schema-benchmark), support data type coercion, this feature is very suit for query parameters, because *querystring* always pase json value as string. But at this moment, It is not support add custom format to other data type, except *string*. -* tv4 Not support data type coercion, but support add custom fromat to all data type. -* null Not use parameter validator. - -### versioning - -boolean optional default true - -Add the major version of api doc to the api endpoint. You also can use **basePath** to manage the api. - -### apiExplorerVisible - -boolean optional default true - -Show api-explorer. Showing on production is not recommended. - -### apiExplorerPath - -string optional default */api-explorer* - -The path of *api-explorer*. - -### apiExplorerStaticPath - -string optional default*/koa-oai-router* - -Static file path of swagger-ui is only set when your static file path is */koa-oai-router*. - -### jsonSchemaFormatters - -object optional default {} - -You can add custom format validation through this. - -Key in object is the **format** keyword. - -Value in object must be a function with parameters **data** and **schema**. - -* data filed to validate -* schema - -When it is valid you should return **null**. When it is invalid you should return error **string**. - -Return what kind of result depends on which validator you choice. +app.listen(3000); +``` -- ajv if valid return true, otherwise return false. -- tv4 if valid return null, otherwise return error message string. +## Creating business middleware +Create business middleware directory `controllers` and write business middleware. +```js +// ./controllers/pets.js -```javascript -import Koa from ('koa'); -import bodyParser from ('koa-bodyparser'); -import Router from ('koa-oai-router'); +const database = []; -const app = new Koa(); -const server= app.listen(9000); +// Query pets in the database according to tags, and limit the query result according to the limit. +async function get(ctx, next) { + const { tags = '', limit = 999 } = ctx.request.query; + const tagsArray = tags.split(','); + const docs = []; -app.use(bodyParser()); - -var opt = { - apiDoc: './api/api.yaml', - controllerDir: './controllers', - server: server - jsonSchemaFormatters: { - "zh-CN": (data, schema)=> { - return data !== 'zh-CN' ? null : 'language is not zh-CN'; + database.forEach((item, idx) => { + if (tagsArray.indexOf(item.tag) !== -1 && docs.length < limit) { + item.id = idx + 1; + docs.push(item); } - } -}; - -const router = new Router(opt); -app.use(router.routes()); -app.use(router.apiExplorer()); -``` - -### errorHandler + }); -function optional [default error handler](#error-handle) - -You can design your custom error handler by doing this. The function has parameters **error, ctx, schema**. The returned value is response to the reqeust. - -* error Error, created by [http-errors](https://github.com/jshttp/http-errors). if HTTP status code is 400, the error will have extra keywords below. - * type string invalid parameter type, *header, path, query, body* - * path string invalid parameter's path - * error string invalid message - * data object data been validated - * detail object the original error -* ctx koa ctx -* schema Json Schema of the api + ctx.response.body = docs; +} -### defaultResponseSchemas +// Create a pet store to the database. +async function post(ctx, next) { + const body = ctx.request.body; -Define default response schemas, if you don't want to write response schema under every api. + database.push(body); -```js -const commonSchema = { - type: 'object', - properties: { - error_code: { - type: 'number', - }, - error_description: { - type: 'string', - }, - }, -}; + ctx.response.body = { + id: database.length, + name: body.name, + tag: body.tag, + }; +} -const schemas = { - 401: { - title: 'Unauthorized', - schema: commonSchema, - }, - 402: { - title: 'PaymentRequired', - schema: commonSchema, - }, - 403: { - title: 'Forbidden', - schema: commonSchema, - }, - 404: { - title: 'NotFound', - schema: commonSchema, - }, - 429: { - title: 'TooManyRequests', - schema: commonSchema, - }, - 500: { - title: 'InternalError', - schema: commonSchema, - }, +module.exports = { + get, + post, }; ``` -## Router.routes() - -Return router middleware which dispatches a route matching the request. - -## Router.apiExplorer() - -Return router middleware which mounts swagger-ui 2.x. Open **/api-explorer** to explorer you api. - -## Router.apiExplorerV3() +## Creating api doc +If you know nothing about [OpenAPI][oai], please read [OpenAPI][oai] carefully. -Return router middleware which mounts swagger-ui 3.x. Open **/api-explorer-v3** to explorer you api. swagger-ui 3.x supports 2.x specification. - -## Router.use(keyword, fn) - -Through this, you can extend plugin to handle options which starts with **x-oai-** in apiDoc. +### Writing api base info +You can describe the basic information of the service, such as the version of the service, the basic path, transmission protocol, author and permission license. +```yaml +# ./api/api.yaml -* keyword starts with **x-oai-** , not including **x-oai-controller**. -* fn is handler of keywords. +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 +``` -For example,we need to configure cache expired time for api through apiDoc. We can extend plugin based on following steps. +### Writing `paths` info +Holds the relative paths to the individual endpoints. The path is appended to the basePath in order to construct the full URL. Please refer to [Paths][oai-paths]. ```yaml -# First,configure cache expired time at apiDoc. -# x-oai-cache: -# expire: 86400 -# api.yaml +# ./api/paths/pets.yaml -/users/{userId}: +/pets: get: + description: "Returns all pets from the system that the user has access to" + operationId: "findPets" + produces: + - "application/json" tags: - - User - description: find a user by userId - x-oai-cache: - expire: 86400 - x-oai-controller: - - file: people + - pets + x-oai-middleware: + - file: pets handler: get parameters: - - name: userId - in: path + - 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 - type: number + schema: + $ref: "#/definitions/NewPet" responses: + "200": + description: "pet response" + schema: + $ref: "#/definitions/Pet" default: - description: unexpected error + description: "unexpected error" schema: - $ref: '#/definitions/Error' -``` - -```js -/* - * Second,develop x-oai-cahce plugin. - * Export a function with a argument, and return a koa middleware. - */ -export default (config) => { - // config is {expire: 86400} - return (ctx, next) => { - // write your code. - } -} + $ref: "#/definitions/ErrorModel" ``` -```js -/* - * Third,mount your plugin to router with keyword. - */ -var router = new Router(opt); - -var cachePlugin = new Cache({ - store: new Redis() -}); - -router.use('x-oai-cache', cachePlugin); - -app.use(router.routes()); -app.use(router.apiExplorer()); -``` - -## Router.extend(endpoint, fn) - -TODO - -## Contrller - -**koa-oai-router** enlarges OpenAPI, now we will recognize **x-oai-controller** keyword in all **method**. - -**x-oai-controller** is an object array and every element must include **file** and **handler**. - -Handler will be executed from up to down, if you have multi handlers. Eg, *acl.isAdmin* will be executed before *people.get* +### Writing `definitions` info +You can define an object to hold data types that can be consumed and produced by operations. These data types can be primitives, arrays or models. Please refer to [Definitions][oai-definitions]. +1.Define interface error response data model `ErrorModel`. ```yaml -paths: - /people: - get: - tags: - - People - description: find a people by name or mobile - x-oai-controller: - - file: acl - handler: isAdmin - - file: people - handler: get +# ./api/definitions/error.yaml + +ErrorModel: + type: "object" + required: + - "code" + - "message" + properties: + code: + type: "integer" + format: "int32" + message: + type: "string" ``` -### file - -The controller's file path was related to **controllerDir**. - -### handler - -The function is exported from the **file**. The following functions are same to [koa@next](https://github.com/koajs/koa/tree/v2.x#common-function). - -* support common function -* support async function -* support generator function - -## Parameter validate - -Validation is based on [JSON-Schema Draft 4](http://json-schema.org/latest/json-schema-core.html#anchor8), and it enlarges some OpenAPI's format, like *int32,int64,float,double*. - -At this moment **query, body, path and header** is supported. The validate order is *header -> path -> query -> body*. Any step validate failed will throw HTTP 400 error and response error message. - -Recommended Reading: - -[OpenAPI data types and format](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types) - -[OpenAPI parameter object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameterObject) - -### header - -Validate the header of request. - +2.Define query success response data model `Pet`, define new request data model `NewPet`. ```yaml -paths: - /users: - get: - summary: List all users - parameters: - - name: token - in: header - description: token to be passed as a header - required: true - type: string +# ./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" ``` -### path - -Validate the path, multi path parameters are supported. If **peopleId** is missing, the route will not be macthed. At this moment, validation of path only support data type and format. - -**Notice: Path parameter syntax in OpenAPI is "{pathId}".** - -```yaml -paths: - /user/{peopleId}: - get: - summary: pet - parameters: - - name: peopleId - in: path - description: peopleId'id - required: true - type: string -``` - -### query(formData) - -Validate query parameter. Multi query parameters are supported. - -```yaml -paths: - /users: - get: - summary: find a user by name - parameters: - - name: name - in: query - description: name of user - required: true - type: string -``` - -### body - -Validate body parameter, the *id* and *name* are required. - -**NOTICE: OpenAPI2.0 Specification only supports one request body. If a api has multi body, the first body will be validated.** +## Enjoying api-explorer +Start WEB service, test interface and enjoy api-explorer. -```yaml -paths: - /user: - post: - summary: add user - parameters: - - name: user - in: body - description: user to add to the system - required: true - schema: - $ref: '#/definitions/User' -definitions: - User: - required: - - id - - name - properties: - id: - type: integer - format: int64 - name: - type: string - tag: - type: string -``` - -## Response validate(incomplete) - - - -## Error handle - -If the default error handler is not fit you, you can design your custom error handler. The default error handler will get the response's schema by HTTP status code(if not, using default). Then it will pick schema's properties from the error. - -```yaml -swagger: '2.0' -info: - version: 1.0.0 - title: koa-oai-router -consumes: - - application/json -produces: - - application/json -basePath: /api -paths: - /user: - get: - x-oai-controller: - - file: people - handler: get - parameters: - - name: name - in: query - type: string - required: true - responses: - 200: - description: user's info - schema: - $ref: '#/definitions/User' - default: - description: unexpected error - schema: - $ref: '#/definitions/Error' -definitions: - User: - required: - - id - - name - properties: - id: - type: integer - format: int64 - name: - type: string - tag: - type: string - Error: - title: Error - type: object - required: - - status - - error - properties: - status: - type: integer - type: - type: string - path: - type: string - error: - type: string - detail: - type: object -``` +```bash +> 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}] -When page is not inputed, the api will send HTTP 400 with the response body handled by error handler. - -```json -{ - "status": 400, - "type": "query", - "path": "", - "error": "Missing required property: page", - "data": {}, - "detail": { - "message": "Missing required property: page", - "params": { - "key": "page" - }, - "code": 302, - "dataPath": "", - "schemaPath": "/required/0", - "subErrors": null, - "stack": "...." - } -} ``` - +As you can see, all of the business middleware we wrote has been called normally. +Use a browser to open `http://localhost:3000/api-explorer`, and you can enjoy api-explorer now. +![Api Explorer][api-explorer-img] + +# Documentation +* [Usage Guides][usage-guides] +* [References ][references] +* [Migration ][migration] +* [Examples ][oai-router-examples] + +# Ecosystem + +|name|description|status| +|---|---|---| +|[koa-oai-router-middleware][oai-router-middleware]|middleware loader|Developing| +|[koa-oai-router-correction][oai-router-correction]|form correction|Developing| +|[koa-oai-router-parameters][oai-router-parameters]|form validator|Developing| +|[koa-oai-router-responses][oai-router-responses]|response handler|Developing| +|[koa-oai-router-cache][oai-router-cache]|request cache|Planning| +|[koa-oai-router-rbac][oai-router-rbac]|request rbac|Planning| +|koa-oai-router-mongo|MongoDB REST server|Planning| # Plan -* ~~Support OpenAPI/Swagger1.x~~ * Support OpenAPI/Swagger3.0 -* Support OpenAPI/Swagger2.0 Security keyword -* Support Response validate -* Research more Json Schema validator -* More unit test +* More plugins +* More unit tests * Benchmark diff --git a/README.zh-CN.md b/README.zh-CN.md index d831052..059c2e4 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -8,8 +8,6 @@ [![Downloads][downloads-image]][downloads-url] [![Dependency Status][david-img]][david-url] -[![NPM](https://nodei.co/npm/koa-oai-router.png?downloads=true&stars=true)](https://nodei.co/npm/koa-oai-router/) - [travis-img]: https://travis-ci.org/BiteBit/koa-oai-router.svg?branch=master [travis-url]: https://travis-ci.org/BiteBit/koa-oai-router [coveralls-img]: https://coveralls.io/repos/github/BiteBit/koa-oai-router/badge.svg?branch=master @@ -24,12 +22,30 @@ [license-url]: http://opensource.org/licenses/MIT [node-image]: https://img.shields.io/badge/node.js-v4.0.0-blue.svg [node-url]: http://nodejs.org/download/ +[koa-router]: https://github.com/alexmingoia/koa-router +[oai]: https://github.com/OAI/OpenAPI-Specification +[swagger]: http://swagger.io +[swagger-ui]: http://swagger.io/swagger-ui +[jsonschema]: http://json-schema.org +[oai-paths]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#pathsObject +[oai-definitions]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#definitionsObject +[oai-router-middleware]: https://github.com/oaijs/koa-oai-router-middleware +[oai-router-parameters]: https://github.com/oaijs/koa-oai-router-parameters +[oai-router-responses]: https://github.com/oaijs/koa-oai-router-responses +[oai-router-correction]: https://github.com/oaijs/koa-oai-router-correction +[oai-router-cache]: https://github.com/oaijs/koa-oai-router-cache +[oai-router-rbac]: https://github.com/oaijs/koa-oai-router-rbac +[oai-router-examples]: https://github.com/oaijs/koa-oai-router-examples +[migration]: ./docs/zh/migration.md +[usage-guides]: ./docs/zh/usage-guides.md +[references]: ./docs/zh/references.md +[api-explorer-img]: ./docs/api-explorer.png?raw=true [中文](./README.zh-CN.md) [English](./README.md) -我使用过Markdown,Wiki管理接口文档,过程实在难以称得上美好,工作量巨大并且十分无趣。接口的变更需要维护相关文档;接口无法方便地进行调试、测试;以及接口的管理完全依赖于人。这些问题不仅导致接口文档难以维持很高的质量,而且还会让开发人员花费更多的时间在接口调试上,甚至影响项目进度。最最最重要的是,这可能会影响到我们的心情,这可是无法忍受的事情 : ( 。 +我使用过Markdown,Wiki管理接口文档,过程实在难以称得上美好,工作量巨大并且十分无趣。接口的变更需要维护相关文档;接口无法方便地进行调试、测试;以及接口的管理完全依赖于人。这些问题不仅导致接口文档难以维持很高的质量,而且还会让开发人员花费更多的时间在接口调试上,甚至影响项目进度。最最最重要的是,这可能会影响到我们的心情,这可是无法忍受的事情 : ( -于是乎我便四处寻求解决方案,功夫不负有心人。我发现了[The OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification),并且OpenAPI协议生态圈也很完善。[Swagger](http://swagger.io/) 包含了很多工具链,[Swagger UI](http://swagger.io/swagger-ui/)可以自动根据协议文件生成接口文档。而OpenAPI中的数据类型和数据模型是基于[JSON-Schema Draft 4](http://json-schema.org/latest/json-schema-core.html#anchor8)。 +于是乎我便四处寻求解决方案,功夫不负有心人。我发现了[OpenAPI Specification][oai],并且OpenAPI协议生态圈也很完善。[Swagger][swagger] 包含了很多工具链,[Swagger UI][swagger-ui]可以自动根据协议文件生成接口文档。而OpenAPI中的数据类型和数据模型是基于[JSON-Schema Draft 4][jsonschema]。 希望此库可以帮到有同样需求的你,happy coding。 @@ -37,722 +53,324 @@ --- -- [Koa-OAI-Router](#koa-oai-router) -- [特性](#%E7%89%B9%E6%80%A7) -- [安装](#%E5%AE%89%E8%A3%85) -- [快速上手](#%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B) - - [新建API描述文档](#%E6%96%B0%E5%BB%BAapi%E6%8F%8F%E8%BF%B0%E6%96%87%E6%A1%A3) - - [新建控制器](#%E6%96%B0%E5%BB%BA%E6%8E%A7%E5%88%B6%E5%99%A8) - - [新建koa app](#%E6%96%B0%E5%BB%BAkoa-app) - - [使用api-explorer](#%E4%BD%BF%E7%94%A8api-explorer) -- [使用说明](#%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E) - - [Router的参数](#router%E7%9A%84%E5%8F%82%E6%95%B0) - - [apiDoc](#apidoc) - - [controllerDir](#controllerdir) - - [port](#port) - - [server](#server) - - [validator](#validator) - - [versioning](#versioning) - - [apiExplorerVisible](#apiexplorervisible) - - [apiExplorerPath](#apiexplorerpath) - - [apiExplorerStaticPath](#apiexplorerstaticpath) - - [jsonSchemaFormatters](#jsonschemaformatters) - - [errorHandler](#errorhandler) - - [defaultResponseSchemas](#defaultresponseschemas) - - [Router.routes()](#routerroutes) - - [Router.apiExplorer()](#routerapiexplorer) - - [Router.apiExplorerV3()](#routerapiexplorerv3) - - [Router.use(keyword, fn)](#routerusekeyword-fn) - - [Router.extend(endpoint, fn)](#routerextendendpoint-fn) - - [接口的控制器](#%E6%8E%A5%E5%8F%A3%E7%9A%84%E6%8E%A7%E5%88%B6%E5%99%A8) - - [file](#file) - - [handler](#handler) - - [参数校验](#%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C) - - [header](#header) - - [path](#path) - - [query(formData)](#queryformdata) - - [body](#body) - - [结果校验(暂不支持)](#%E7%BB%93%E6%9E%9C%E6%A0%A1%E9%AA%8C%E6%9A%82%E4%B8%8D%E6%94%AF%E6%8C%81) - - [错误处理](#%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86) -- [计划](#%E8%AE%A1%E5%88%92) + + + +* [Koa-OAI-Router](#koa-oai-router) +* [特性](#特性) +* [迁移](#迁移) +* [安装](#安装) +* [快速入门](#快速入门) + * [编写WEB服务](#编写web服务) + * [编写业务中间件](#编写业务中间件) + * [编写Api描述文档](#编写api描述文档) + * [编写基础信息](#编写基础信息) + * [编写`paths`信息](#编写paths信息) + * [编写`definitions`信息](#编写definitions信息) + * [体验api-explorer](#体验api-explorer) +* [文档](#文档) +* [生态](#生态) +* [计划](#计划) + + --- # 特性 * 内置Swagger-UI,方便查看、调试接口 -* 使用OpenAPI/Swagger API文档自动生成Koa路由,并支持参数校验 * 支持OpenAPI/Swagger2.0规范,支持json、yaml格式 -* 支持基于JsonSchema V4的接口query、body、path、header参数校验 -* 支持自定义JsonSchema format校验 -* 支持自定义接口错误处理 - -# 安装 - -> For koa@>=2.x (next): - -```bash -npm install koa-oai-router@next --save -``` - -> For koa@<2.x: - -**暂不支持!** - -# 快速上手 - -## 新建API描述文档 -如果你不了解如何新建该文件,请参考[OpenAPI](https://github.com/OAI/OpenAPI-Specification)。 - -```yaml -# api/api.yaml - -swagger: '2.0' -info: - version: 1.0.0 - title: koa-oai-router -consumes: - - application/json -produces: - - application/json -basePath: /api -paths: - /people: - get: - tags: - - People - description: find a people by name or mobile - x-oai-controller: - - file: people - handler: get - parameters: - - name: name - in: query - type: string - - name: mobile - in: query - type: string - responses: - 200: - description: people's info - schema: - $ref: '#/definitions/People' - default: - description: unexpected error - schema: - $ref: '#/definitions/Error' - post: - tags: - - People - description: input a people's info - x-oai-controller: - - file: people - handler: post - parameters: - - name: body - in: body - required: true - schema: - $ref: '#/definitions/People' - responses: - 200: - description: people's info - schema: - $ref: '#/definitions/People' - default: - description: unexpected error - schema: - $ref: '#/definitions/Error' -definitions: - People: - type: object - required: - - name - - sex - - height - - weight - properties: - name: - type: string - sex: - type: string - enum: - - male - - female - height: - type: integer - format: int32 - minimum: 10 - maximum: 1000 - weight: - type: number - format: float - minimum: 50 - maximum: 200 - mobile: - type: string - Error: - title: Error - type: object - required: - - status - - error - properties: - status: - type: integer - path: - type: string - error: - type: string - detail: - type: object -``` - -## 新建控制器 +* 支持更友好、方便的API文档切分方案 +* 支持自定义插件(中间件加载、表单校验、响应处理、错误处理等将以插件形式提供) +* 继承自[Koa-Router][koa-router],保持原功能、特性,性能。 -在这里添加你的业务逻辑 +# 迁移 +如果你不是1.x的用户,请直接跳过本部分内容。 +如果你是1.x的用户并且想升级到2.0版本,很抱歉你将无法傻瓜式的升级到2.0版本,请仔细阅读本部分的内容[Migration][migration]并且按照操作手册升级。 -```javascript -// controllers/people.js - -var people = {name: 'BiteBit'}; - -function get(ctx, next) { - ctx.body = people; -} - -function post(ctx, next) { - people = ctx.request.body; - ctx.body = people; -} - -module.exports = { - get: get, - post: post -}; +# 安装 +```sh +# required koa 2.x +> npm install koa-oai-router --save ``` -## 新建koa app - +# 快速入门 +下面将带你学习如何使用router构建一个良好组织结构和配备接口文档的Web Server。 +本例中基本涉及了router的所有重点内容,包括: +* 配置router +* 配置插件 +* 挂载插件到router +* 挂载router到app +* 编写接口描述文档 +* 使用插件 +* 使用api-explorer + +我们的目标是: +* 创建一个REST API Server +* 编写一个pets查询接口,并返回查询到的pets数组 +* 编写一个pets新建接口,并返回pet和id +* 生成接口文档,体验api-explorer + +下面我们就正式开始喽。 + +## 编写WEB服务 ```javascript -// app.js +// ./app.js -import Koa from ('koa'); -import bodyParser from ('koa-bodyparser'); -import Router from ('koa-oai-router'); +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(); -const server = app.listen(9000); -app.use(bodyParser()); +// *配置router - 从api目录下加载接口描述并生成api文档 +const router = new Router({ + apiDoc: './api', +}); -// 配置koa-oai-router选项 -var opt = { - // API文档路径 - apiDoc: './api/api.yaml', - // controllers的目录 - controllerDir: './controllers', - // 从server中获取监听的端口,为了方便打开api-explorer - server: server, - // 对接口做版本控制 - versioning: true, - // 展示api-explorer - apiExplorerVisible: true -}; +// *配置插件 - 识别api文档中的x-oai-middleware并从controllers中加载相应的中间件 +// *挂载插件到router +router.mount(middleware('./controllers')); -var router = new Router(opt); -// 挂载由apiDoc识别的接口 +app.use(logger()); +app.use(bodyParser()); +// *挂载router到app app.use(router.routes()); -// 挂载api-explorer工具 -app.use(router.apiExplorer()); -``` - -## 使用api-explorer - -根据提示,用浏览器打开http://127.0.0.1:9000/api-explorer,测试你的接口吧! - -![Api Explorer](./images/api-explorer.png?raw=true) - -# 使用说明 - -## Router的参数 - -### apiDoc - -string 必须 - -api描述文件的路径,目前支持OpenAPI2.0的json/yaml格式文件。 -### controllerDir - -string 必须 - -控制器所在的文件夹目录,主要的业务逻辑处理入口。 - -### port - -number 可选 默认80 - -koa服务监听的端口,用于生成api-explorer链接提示信息。 - -### server - -net.Socket 可选 - -koa服务监听时返回的Socket,用于自动获取服务的端口,也是用于生成api-explorer链接提示信息。当*port*与*server*同时指定时,优先使用*port*。*server*与*port*设置其一即可。 - -### validator - -string 可选 默认ajv - -选择使用的校验引擎[ajv](https://github.com/epoberezkin/ajv),[tv4](https://github.com/geraintluff/tv4)或者设置**null**不使用校验引擎。这两个校验引擎并不是都很完美,我任然在寻找更合适的校验引擎 - -* ajv 在Json Schema的[Benchmark ](https://github.com/ebdrup/json-schema-benchmark)中表现最优秀,并且支持数据类型被动转换,这个特性很适合做query的校验,因为querystring解析出Json Object的值总是字符串类型。但是目前对于Json Schema的自定义format支持仅限于string类型。 -* tv4 在Json Schema的[Benchmark ](https://github.com/ebdrup/json-schema-benchmark)中表现一般,不支持数据类型的被动转换。但是对于Json Schema的自定义format支持不限于string类型。 - -### versioning - -boolean 可选 默认true - -是否使用主版本号对接口做版本管理。即如果API描述文档版本号是"1.2.3",那么接口地址会自动增加"/v1/xxx"的前缀。 -如果想在接口中体现更多的版本信息,可关闭该选项,在API描述文档中的basePath字段手动管理。 - -### apiExplorerVisible - -boolean 可选 默认true - -是否显示api-explorer,建议生产环境不要显示api-explorer。 - -### apiExplorerPath - -string 可选 默认*/api-explorer* - -api-explorer工具的路径。 - -### apiExplorerStaticPath - -string 可选(不推荐设置) 默认*/koa-oai-router* - -swagger-ui静态资源的目录,除非和你的静态资源目录发生冲突。 - -### jsonSchemaFormatters - -object 可选 默认{} - -是否为Json Schema添加自定义format校验器。 - -object的key为自定义format的关键字。 -object的key对应的value是一个函数。参数列表为(data, schema)。 - -* data 需要校验的数据。 -* schema 该数据对应的Json Schema。 - -校验结果依赖于你使用哪个校验引擎。 - -* ajv 校验函数返回true表示通过,返回false表示校验失败。 -* tv4 校验函数返回null表示校验通过,返回string表示校验失败(该错误字符串将作为错误信息)。 +app.listen(3000); +``` -```javascript -import Koa from ('koa'); -import bodyParser from ('koa-bodyparser'); -import Router from ('koa-oai-router'); +## 编写业务中间件 +创建业务中间件目录`controllers`并编写业务中间件。 +```js +// ./controllers/pets.js -const app = new Koa(); -const server= app.listen(9000); +const database = []; -app.use(bodyParser()); +// 根据tags查询数据库中的pets,并根据limit限制查询结果。 +async function get(ctx, next) { + const { tags = '', limit = 999 } = ctx.request.query; + const tagsArray = tags.split(','); + const docs = []; -var opt = { - apiDoc: './api/api.yaml', - controllerDir: './controllers', - server: server - jsonSchemaFormatters: { - "zh-CN": (data, schema)=> { - return data !== 'zh-CN' ? null : 'language is not zh-CN'; + database.forEach((item, idx) => { + if (tagsArray.indexOf(item.tag) !== -1 && docs.length < limit) { + item.id = idx + 1; + docs.push(item); } - } -}; - -const router = new Router(opt); -app.use(router.routes()); -app.use(router.apiExplorer()); -``` - -### errorHandler - -function 可选 [默认处理函数](#) + }); -如果想自己实现错误结果定义,那么你需要实现该函数,该函数有三个参数(error, ctx, schema),并返回处理结果。 - -* error Error对象,由[http-errors](https://github.com/jshttp/http-errors)创建。如果是400错误,那么error对象额外包含以下字段 - * type string 校验失败的参数类型,header, path, query和body。 - * path string 参数校验失败的字段 - * error string 参数校验失败的错误提示 - * data object 参与校验的参数 - * detail object 校验失败原始错误 -* ctx -* schema 该接口的schema + ctx.response.body = docs; +} -### defaultResponseSchemas +// 新建一个pet存储到数据库中。 +async function post(ctx, next) { + const body = ctx.request.body; -定义一个默认的响应schema。 + database.push(body); -```js -const commonSchema = { - type: 'object', - properties: { - error_code: { - type: 'number', - }, - error_description: { - type: 'string', - }, - }, -}; + ctx.response.body = { + id: database.length, + name: body.name, + tag: body.tag, + }; +} -const schemas = { - 401: { - title: 'Unauthorized', - schema: commonSchema, - }, - 402: { - title: 'PaymentRequired', - schema: commonSchema, - }, - 403: { - title: 'Forbidden', - schema: commonSchema, - }, - 404: { - title: 'NotFound', - schema: commonSchema, - }, - 429: { - title: 'TooManyRequests', - schema: commonSchema, - }, - 500: { - title: 'InternalError', - schema: commonSchema, - }, +module.exports = { + get, + post, }; ``` +## 编写Api描述文档 +如果你还不了解[OpenAPI][oai],请仔细阅读[OpenAPI][oai]。 +### 编写基础信息 +在这里你可以对服务的基础信息进行描述,如服务的版本,基础路径,传输协议,作者,许可协议等。 +```yaml +# ./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 +``` - -## Router.routes() - -Return router middleware which dispatches a route matching the request. - -## Router.apiExplorer() - -Return router middleware which mounts swagger-ui 2.x. Open **/api-explorer** to explorer you api. - -## Router.apiExplorerV3() - -Return router middleware which mounts swagger-ui 3.x. Open **/api-explorer-v3** to explorer you api. swagger-ui 3.x support 2.x specification - -## Router.use(keyword, fn) - -通过此你可以为router设置插件,自定义处理apiDoc中的以**x-oai-**开头的选项。 - -* keyword是以**x-oai-**开头且不是**x-oai-controller**的字符串 -* fn对应keyword的处理器 - -例如,我们需要通过apiDoc配置指定接口的缓存时间,我们可以通过如下步骤完成插件。 +### 编写`paths`信息 +编写api接口描述信息,这里的path是一个相对路径。path会追加在basePath的后面组成一个完成的URL,其他字段描述了接口的详细信息。详情请参考[Paths][oai-paths]。 ```yaml -# 第一步,在apiDoc中为接口配置缓存时长信息 -# x-oai-cache: -# expire: 86400 -# api.yaml +# ./api/paths/pets.yaml -/users/{userId}: +/pets: get: + description: "Returns all pets from the system that the user has access to" + operationId: "findPets" + produces: + - "application/json" tags: - - User - description: find a user by userId - x-oai-cache: - expire: 86400 - x-oai-controller: - - file: people + - pets + x-oai-middleware: + - file: pets handler: get parameters: - - name: userId - in: path + - 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 - type: number + schema: + $ref: "#/definitions/NewPet" responses: + "200": + description: "pet response" + schema: + $ref: "#/definitions/Pet" default: - description: unexpected error + description: "unexpected error" schema: - $ref: '#/definitions/Error' -``` - -```js -/* - * 第二步,开发x-oai-cache插件 - * 获取apiDoc中x-oai-cache选项的配置信息,并返回一个koa中间件 - */ -export default (config) => { - // config 内容为 {expire: 86400} - return (ctx, next) => { - // 开发你的插件业务 - } -} -``` - -```js -/* - * 第三步,将你的业务插件挂载在路由上 - */ -var router = new Router(opt); - -var cachePlugin = new Cache({ - store: new Redis() -}); - -router.use('x-oai-cache', cachePlugin); - -app.use(router.routes()); -app.use(router.apiExplorer()); + $ref: "#/definitions/ErrorModel" ``` -## Router.extend(endpoint, fn) - -TODO - -## 接口的控制器 - -**koa-oai-router**对OpenAPI进行了扩展,会识别API文档中每个path下的method中包含的**x-oai-controller**字段。 - -**x-oai-controller**是一个对象数组,每个元素均需包含参数**file**和**handler**。 - -**如果x-oai-controller包含多个元素,那么中间件处理的优先级按照由上至下依次进行。** - +### 编写`definitions`信息 +你可以通过definitions定义一些常用的数据模型,这些模型可以很方便地复用在请求参数或者响应结果的定义中,减少文档的“坏味道”。这些数据模型可以是基础数据类型、数组、复杂的JSON对象,详情请参考[Definitions][oai-definitions]。 +1.定义接口错误响应数据模型ErrorModel。 ```yaml -paths: - /people: - get: - tags: - - People - description: find a people by name or mobile - x-oai-controller: - - file: acl - handler: isAdmin - - file: people - handler: get +# ./api/definitions/error.yaml + +ErrorModel: + type: "object" + required: + - "code" + - "message" + properties: + code: + type: "integer" + format: "int32" + message: + type: "string" ``` -### file - -表示该接口对应控制器文件的名称。 - -### handler - -控制器文件导出的函数。[koa@next](https://github.com/koajs/koa/tree/v2.x#common-function) - -* 支持common function -* 支持async function -* 支持generator function - -## 参数校验 - -参数校验基于Json Schema,目前支持query(formData),body,path,header四种类型的参数校验。 - -校验的顺序是:header -> path -> query -> formData -> body,其中任何一部校验失败,接口报错HTTP 400错误,并返回相关错误提示。 - -详细请深入了解以下文档: - -[OpenAPI的data types以及format](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types) - -[OpenAPI的参数校验规范](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameterObject) - -### header - -```yaml -paths: - /users: - get: - summary: List all users - parameters: - - name: token - in: header - description: token to be passed as a header - required: true - type: string -``` - -校验接口请求的header中是否包含token字段,并且要求为string类型。支持多个header参数同时校验。 - -### path - -```yaml -paths: - /user/{peopleId}: - get: - summary: pet - parameters: - - name: peopleId - in: path - description: peopleId'id - required: true - type: string -``` - -如果你未传入**peopleId**,那么路由将无法被匹配到,而不是提示HTTP 400参数校验失败,目前只支持对path的参数类型,格式做校验并不支持required的校验。支持多个path参数同时校验。 - -### query(formData) - +2.定义查询成功响应数据模型Pet,定义新增请求数据模型NewPet。 ```yaml -paths: - /users: - get: - summary: find a user by name - parameters: - - name: name - in: query - description: name of user - required: true - type: string +# ./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" ``` -校验接口的query参数是否为存在并且为字符串。支持多个query参数同时校验。 - -### body - -```yaml -paths: - /user: - post: - summary: add user - parameters: - - name: user - in: body - description: user to add to the system - required: true - schema: - $ref: '#/definitions/User' -definitions: - User: - required: - - id - - name - properties: - id: - type: integer - format: int64 - name: - type: string - tag: - type: string -``` - -校验接口的body参数,其中id和name是必须字段。 - -**注意:OpenAPI2.0规范定义每个接口中仅支持一个body参数,如果API描述文档中包含多个body,那么只会校验第一个body**。 - -## 结果校验(暂不支持) - - - -## 错误处理 - -如果接口抛出异常,那么错误处理函数将会捕捉到异常并处理。默认错误处理函数会根据抛出异常的HTTP状态码获取API文档中设置的response相匹配的schema(如果未找到,那么使用default)。然后会从Error对象中Pick出该schema中定义的所有字段。 - -```yaml -swagger: '2.0' -info: - version: 1.0.0 - title: koa-oai-router -consumes: - - application/json -produces: - - application/json -basePath: /api -paths: - /user: - get: - x-oai-controller: - - file: people - handler: get - parameters: - - name: name - in: query - type: string - required: true - responses: - 200: - description: user's info - schema: - $ref: '#/definitions/User' - default: - description: unexpected error - schema: - $ref: '#/definitions/Error' -definitions: - User: - required: - - id - - name - properties: - id: - type: integer - format: int64 - name: - type: string - tag: - type: string - Error: - title: Error - type: object - required: - - status - - error - properties: - status: - type: integer - type: - type: string - path: - type: string - error: - type: string - detail: - type: object -``` +## 体验api-explorer +启动WEB服务,测试接口,体验api-explorer。 +```bash +> 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 400错误的时候,接口返回以下结果: - -```json -{ - "status": 400, - "type": "query" - "path": "", - "error": "Missing required property: page", - "data": {}, - "detail": { - "message": "Missing required property: page", - "params": { - "key": "page" - }, - "code": 302, - "dataPath": "", - "schemaPath": "/required/0", - "subErrors": null, - "stack": "...." - } -} ``` - +可以看到,我们编写的业务中间件都已经被正常调用了。 +使用浏览器打开**http://localhost:3000/api-explorer**,现在你可以体验api-explorer了。 +![Api Explorer][api-explorer-img] + +# 文档 +* [Usage Guides][usage-guides] +* [References ][references] +* [Migration ][migration] +* [Examples ][oai-router-examples] + +# 生态 + +|名称|描述|状态| +|---|---|---| +|[koa-oai-router-middleware][oai-router-middleware]|业务中间件加载|开发中| +|[koa-oai-router-correction][oai-router-correction]|请求表单预处理|开发中| +|[koa-oai-router-parameters][oai-router-parameters]|请求表单校验|开发中| +|[koa-oai-router-responses][oai-router-responses]|请求结果处理|开发中| +|[koa-oai-router-cache][oai-router-cache]|请求缓存插件|计划中| +|[koa-oai-router-rbac][oai-router-rbac]|请求权限控制|计划中| +|koa-oai-router-mongo|MongoDB REST server|计划中| # 计划 -* ~~支持OpenAPI/Swagger1.x规范~~ -* 支持OpenAPI/Swagger3.0规范 -* 支持OpenAPI/Swagger2.0协议中的Security校验 -* 支持接口的返回结果校验 -* 更多的Json Schema校验引擎调研 +* 支持OpenAPI 3.x规范 +* 更多的插件 * 更多的单元测试 * Benchmark diff --git a/docs/api-explorer.png b/docs/api-explorer.png new file mode 100644 index 0000000..b14b8c6 Binary files /dev/null and b/docs/api-explorer.png differ diff --git a/docs/en/migration.md b/docs/en/migration.md new file mode 100644 index 0000000..8eb30ea --- /dev/null +++ b/docs/en/migration.md @@ -0,0 +1,135 @@ + + + +* [Changes in 2.0](#changes-in-20) + * [Remove the option controllerDir](#remove-the-option-controllerdir) + * [Remove the option port](#remove-the-option-port) + * [Remove the option server](#remove-the-option-server) + * [Remove the option versioning](#remove-the-option-versioning) + * [Remove the option apiExplorerPath](#remove-the-option-apiexplorerpath) + * [Remove the option apiExplorerStaticPath](#remove-the-option-apiexplorerstaticpath) + * [Remove the option validator](#remove-the-option-validator) + * [Remove the option jsonSchemaFormatters](#remove-the-option-jsonschemaformatters) + * [Remove the option errorHandler](#remove-the-option-errorhandler) + * [Remove the option defaultResponseSchemas](#remove-the-option-defaultresponseschemas) + * [Remove function router.apiExplorer()](#remove-function-routerapiexplorer) + * [Remove function router.apiExplorerV3()](#remove-function-routerapiexplorerv3) + * [Remove function router.use(keyword, fn)](#remove-function-routerusekeyword-fn) + * [Remove function router.extend(endpoint, fn)](#remove-function-routerextendendpoint-fn) + + + +[koa-router]: https://github.com/alexmingoia/koa-router +[oai-router-middleware]: https://github.com/oaijs/koa-oai-router-middleware +[oai-router-parameters]: https://github.com/oaijs/koa-oai-router-parameters +[oai-router-responses]: https://github.com/oaijs/koa-oai-router-responses +[oai-router-correction]: https://github.com/oaijs/koa-oai-router-correction +[oai-router-cache]: https://github.com/oaijs/koa-oai-router-cache +[oai-router-rbac]: https://github.com/oaijs/koa-oai-router-rbac +[references-plugin]: ./references.md#plugin + +# Changes in 2.0 +Sorry, 1.x can not be easily upgraded to 2.0 for the sake of simplicity, elegance, maintainability, and extendibility. I want to build a good project, to solve some of the problems we actually encounter better. + +If you are using the following features, please migrate as the document says. + +## Remove the option controllerDir +Middleware loader is no longer built-in, supported by [koa-oai-router-middleware][oai-router-middleware]. Please refer to the following code: +```js +const Koa = require('koa'); +const Router = require('koa-oai-router'); +const middleware = require('koa-oai-router-middleware'); + +const app = new Koa(); + +const router = new Router({ + apiDoc: './api', + options: { + // Attention: `middleware` is name of plugin(defined by the plugin author),`./controllers` is controllerDir + // The key-value pairs in options pass the plug-in parameters to the plug-in based on the plug-in name when the plug-in is called. + middleware: './controllers', + }, +}); + +router.mount(middleware()); + +app.use(router.routes()); + +app.listen(3000); +``` +Or +```js +const Koa = require('koa'); +const Router = require('koa-oai-router'); +const middleware = require('koa-oai-router-middleware'); + +const app = new Koa(); + +const router = new Router({ + apiDoc: './api', +}); + +// Attention: Configure the middleware directory when the plug-in is mounted +router.mount(middleware('./controllers')); + +app.use(router.routes()); + +app.listen(3000); +``` + +## Remove the option port +No longer output api-explorer visit address on console, visit: `http://{ip}:{port}/api-explorer` + +## Remove the option server +No longer output api-explorer visit address on console, visit: `http://{ip}:{port}/api-explorer` + +## Remove the option versioning +Disabled, It can be implemented by the API description `basePath`. api doc: +```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: /v1/api +... +... +``` + +## Remove the option apiExplorerPath +No longer provide customized api-explorer path function, visit: `http://{ip}:{port}/api-explorer` + +## Remove the option apiExplorerStaticPath +No longer supported. + +## Remove the option validator +Form validation is no longer built-in, supported by [koa-oai-router-parameters][oai-router-parameters]. + +## Remove the option jsonSchemaFormatters +Form validation `JSON-Schema formatters` configuration features, supported by [koa-oai-router-parameters][oai-router-parameters]. + +## Remove the option errorHandler +Error handler is no longer built-in, supported by [koa-oai-router-responses][oai-router-responses]. + +## Remove the option defaultResponseSchemas +Error handler `Response Schemas` configuration features is no longer built-in, supported by [koa-oai-router-responses][oai-router-responses]. + +## Remove function router.apiExplorer() +No longer supported swagger-ui 2.x `api-explorer`. +There is no need to mount, it can be control by `apiExplorerVisible`. + +## Remove function router.apiExplorerV3() +There is no need to mount, it can be control by `apiExplorerVisible`. + +## Remove function router.use(keyword, fn) +Please use the new way to mount [Plugin][references-plugin], if the plugin is not supported, please give me an issue. + +## Remove function router.extend(endpoint, fn) +No longer supported. diff --git a/docs/en/references.md b/docs/en/references.md new file mode 100644 index 0000000..2a2b1b1 --- /dev/null +++ b/docs/en/references.md @@ -0,0 +1,170 @@ + + + +* [Router](#router) + * [new Router(options)](#new-routeroptions) + * [router.mount(Plugin)](#routermountplugin) + * [router.get|put|post|patch|delete|del](#routergetputpostpatchdeletedel) + * [router.routes()](#routerroutes) + * [router.use([path], middleware)](#routerusepath-middleware) + * [router.allowedMethods([options])](#routerallowedmethodsoptions) + * [router.redirect(source, destination, [code])](#routerredirectsource-destination-code) + * [router.route(name)](#routerroutename) + * [router.url(name, params, [options])](#routerurlname-params-options) + * [router.param(param, middleware)](#routerparamparam-middleware) + * [Router.url(path, params)](#routerurlpath-params) +* [Plugin](#plugin) + * [new Plugin(options)](#new-pluginoptions) + + + +[router-verbs]: https://github.com/alexmingoia/koa-router#routergetputpostpatchdeletedel--router +[router-routes]: https://github.com/alexmingoia/koa-router#routerroutes--function +[router-use]: https://github.com/alexmingoia/koa-router#routerusepath-middleware--router +[router-allowmethods]: https://github.com/alexmingoia/koa-router#routerallowedmethodsoptions--function +[router-redirect]: https://github.com/alexmingoia/koa-router#routerredirectsource-destination-code--router +[router-route]: https://github.com/alexmingoia/koa-router#routerroutename--layer--false +[router-url]: https://github.com/alexmingoia/koa-router#routerurlname-params-options--string--error +[router-param]: https://github.com/alexmingoia/koa-router#routerparamparam-middleware--router +[Router-url]: https://github.com/alexmingoia/koa-router#routerurlpath-params--string +[oai-fields]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields-5 + +# Router +Inherited from [koa-router](https://github.com/alexmingoia/koa-router), in addition to that the `prefix` option is not supported temporarily, to maintain other original function, features and performance. And some new features added. + +## new Router(options) + +* `options` {object} configuration options. Can have the following fields: + * `apiDoc` {string} `required` api document or document directory. When the api document is directory, it will load other files in the directory automatically. + * `apiExplorerVisible` {boolean} `optional` enable `api-explorer`. default `true`. + * `options` {object} `optional` plugin options. `key` is plugin name, `value` is plugin arguments. + +`apiDoc` document can be yaml or json format. When `apiDoc` is a directory, the contents of each api file description directory will be merged into the OpenAPI protocol file. The contents of `/project/paths` will be loaded into the `paths` field of the document, the contents of `/project/definitions` will be loaded into the document's `definitions` field, and the other folders will not be loaded. + +api document directory structure is as follows: +* `project` + * `api.yaml` + * `paths` + * `definitions` + * `parameters` + * `responses` + * `securityDefinitions` + * `security` + * `tags` + * `externalDocs` + +There is no need to use any plugins if you only want to use the basic functionality of the router and `api-explorer`. You just need to configure ` apiDoc` and `apiExplorerVisible`. route and middleware need to be bound manually. Here is the code: +```js +const Koa = require('koa'); +const Router = require('koa-oai-router'); + +const app = new Koa(); + +const router = new Router({ + apiDoc: './api', + apiExplorerVisible: true, +}); + +// Manually mount /hello with business middleware +router.get('/hello', (ctx, next) => { + ctx.response.body = 'world'; +}); + +app.use(router.routes()); + +app.listen(3000); +``` + +## router.mount(Plugin) +Mount the plugin to the router, the plugin will be executed with order of mount. +If one of the plugins does not evoke next(), execution of the subsequent plugin chain will be terminated. + +## router.get|put|post|patch|delete|del +Same as koa-router: [router.get|put|post|patch|delete|del][router-verbs] + +## router.routes() +Same as koa-router: [router.routes()][router-routes] + +## router.use([path], middleware) +Same as koa-router: [router.use([path], middleware)][router-use] + +## router.allowedMethods([options]) +Same as koa-router: [router.allowedMethods([options])][router-allowmethods] + +## router.redirect(source, destination, [code]) +Same as koa-router: [router.redirect(source, destination, [code])][router-redirect] + +## router.route(name) +Same as koa-router: [router.route(name)][router-route] + +## router.url(name, params, [options]) +Same as koa-router: [router.url(name, params, [options])][router-url] + +## router.param(param, middleware) +Same as koa-router: [router.param(param, middleware)][router-param] + +## Router.url(path, params) +Same as koa-router: [Router.url(path, params)][Router-url] + + +# Plugin +Plugins can be applied to every api as koa middleware. +Its activation depends on whether the api document contains its activation `field`. Once the plugin is activated, `middlewareWrapper` will be invoked internally and passed in the `(middlewareOpts, middlewareArgs)` parameter and must return a koa middleware that will be mounted on the current api. + +## new Plugin(options) +Create a plugin. + +* `options` {object} Plugin configuration options. Can have the following fields: + * `name` {string} `required` The name of the plugin. Configure the plugin parameters in the router options as the key. + * `field` {string|string[]} `required` Activate field. The plugin is activated when this field is included in the API document. Field range reference [Operation Object][oai-fields]. + * `middlewareWrapper` {object} `required` Plugin logic module, you must return a koa middleware. + * `middlewareArgs` {object} `optional` Plugin global options. + +`middlewareWrapper` Must return a koa middleware, there (middlewareOpts, middlewareArgs) Parameters: +* `middlewareOpts` {object} Information about the current interface document fragment when the plug-in is activated. + * `endpoint` {string} ednpoint + * `field` {string} the keyword when activated + * `fieldValue` {object} The data corresponding to the keyword when it is activated + * `operation` {string} http method + * `operationValue` {object} api's meta data +* `middlewareArgs` {any} Plugin global options. + +`middlewareArgs` can be configured when creating a router and the configuration of this method will have the highest priority. +```js +const plugin = new PluginXXX({ + name: 'pluginXXX', + field: 'parameters', + // middlewareArgs: pluginArgs, + middlewareWrapper: () => { + return (ctx, next) => {return next();}; + }, +}); + +const router = new Router({ + apiDoc: './api', + options: { + pluginXXX: pluginArgs, + } +}); + +router.mount(plugin); +``` + +`middlewareArgs` it can also be configured when creating a plugin, and the method's configuration will have the lowest priority. + +```js +const plugin = new PluginXXX({ + name: 'pluginXXX', + field: 'parameters', + middlewareArgs: pluginArgs, + middlewareWrapper: () => { + return (ctx, next) => {return next();}; + }, +}); + +const router = new Router({ + apiDoc: './api', +}); + +router.mount(plugin); +``` diff --git a/docs/en/usage-guides.md b/docs/en/usage-guides.md new file mode 100644 index 0000000..30404ce --- /dev/null +++ b/docs/en/usage-guides.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/docs/zh/migration.md b/docs/zh/migration.md new file mode 100644 index 0000000..d477023 --- /dev/null +++ b/docs/zh/migration.md @@ -0,0 +1,135 @@ + + + +* [2.0变更](#20变更) + * [去除选项controllerDir](#去除选项controllerdir) + * [去除选项port](#去除选项port) + * [去除选项server](#去除选项server) + * [去除选项versioning](#去除选项versioning) + * [去除选项apiExplorerPath](#去除选项apiexplorerpath) + * [去除选项apiExplorerStaticPath](#去除选项apiexplorerstaticpath) + * [去除选项validator](#去除选项validator) + * [去除选项jsonSchemaFormatters](#去除选项jsonschemaformatters) + * [去除选项errorHandler](#去除选项errorhandler) + * [去除选项defaultResponseSchemas](#去除选项defaultresponseschemas) + * [去除成员函数router.apiExplorer()](#去除成员函数routerapiexplorer) + * [去除成员函数router.apiExplorerV3()](#去除成员函数routerapiexplorerv3) + * [去除成员函数router.use(keyword, fn)](#去除成员函数routerusekeyword-fn) + * [去除成员函数router.extend(endpoint, fn)](#去除成员函数routerextendendpoint-fn) + + + +[koa-router]: https://github.com/alexmingoia/koa-router +[oai-router-middleware]: https://github.com/oaijs/koa-oai-router-middleware +[oai-router-parameters]: https://github.com/oaijs/koa-oai-router-parameters +[oai-router-responses]: https://github.com/oaijs/koa-oai-router-responses +[oai-router-correction]: https://github.com/oaijs/koa-oai-router-correction +[oai-router-cache]: https://github.com/oaijs/koa-oai-router-cache +[oai-router-rbac]: https://github.com/oaijs/koa-oai-router-rbac +[references-plugin]: ./references.md#plugin + +# 2.0变更 +很抱歉,为了项目的简洁、优雅、可维护、可扩展的目的,1.x无法简单升级到2.0。我想构建一个优秀的项目,更好的解决我们实际中遇到的一些问题。 + +如果你有使用到以下变更项,请按照文档变更。 + +## 去除选项controllerDir +加载中间件的功能不再内置,由插件[koa-oai-router-middleware][oai-router-middleware]实现。请参考以下代码: +```js +const Koa = require('koa'); +const Router = require('koa-oai-router'); +const middleware = require('koa-oai-router-middleware'); + +const app = new Koa(); + +const router = new Router({ + apiDoc: './api', + options: { + // 划重点:`middleware`是插件的名称(由插件作者定义),`./controllers`是controllerDir目录 + // options中的键值对将会在调用插件时根据插件名称将插件参数传递给插件。 + middleware: './controllers', + }, +}); + +router.mount(middleware()); + +app.use(router.routes()); + +app.listen(3000); +``` +或者 +```js +const Koa = require('koa'); +const Router = require('koa-oai-router'); +const middleware = require('koa-oai-router-middleware'); + +const app = new Koa(); + +const router = new Router({ + apiDoc: './api', +}); + +// 划重点:在插件挂载时配置中间件目录 +router.mount(middleware('./controllers')); + +app.use(router.routes()); + +app.listen(3000); +``` + +## 去除选项port +不再控制台提示api-explorer访问地址,请访问:`http://{ip}:{port}/api-explorer` + +## 去除选项server +不再控制台提示api-explorer访问地址,请访问:`http://{ip}:{port}/api-explorer` + +## 去除选项versioning +接口版本化不再提供,可由api描述文档`basePath`配置实现。如下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: /v1/api +... +... +``` + +## 去除选项apiExplorerPath +不再提供定制化api-explorer路径的功能,请访问:`http://{ip}:{port}/api-explorer` + +## 去除选项apiExplorerStaticPath +不再提供定制化api-explorer静态资源路径的功能。 + +## 去除选项validator +表单校验功能不再内置,由插件[koa-oai-router-parameters][oai-router-parameters]实现。 + +## 去除选项jsonSchemaFormatters +表单校验的JSON-Schema formatters配置功能,由插件[koa-oai-router-parameters][oai-router-parameters]实现。 + +## 去除选项errorHandler +错误处理功能不再内置,由插件[koa-oai-router-responses][oai-router-responses]实现。 + +## 去除选项defaultResponseSchemas +错误处理的默认Response Schemas配置功能,由插件[koa-oai-router-responses][oai-router-responses]实现。 + +## 去除成员函数router.apiExplorer() +不再提供swagger-ui 2.x版本的`api-explorer`。 +使用`api-explorer`不再需要额外挂载到app上,由`apiExplorerVisible`实现控制。 + +## 去除成员函数router.apiExplorerV3() +使用`api-explorer`不再需要额外挂载到app上,由`apiExplorerVisible`实现控制。 + +## 去除成员函数router.use(keyword, fn) +请使用新的方式挂载插件[Plugin][references-plugin],如果你使用的插件并未得到支持,请提需求。 + +## 去除成员函数router.extend(endpoint, fn) +不再提供。 diff --git a/docs/zh/references.md b/docs/zh/references.md new file mode 100644 index 0000000..7004514 --- /dev/null +++ b/docs/zh/references.md @@ -0,0 +1,171 @@ + + + +* [Router](#router) + * [new Router(options)](#new-routeroptions) + * [router.mount(Plugin)](#routermountplugin) + * [router.get|put|post|patch|delete|del](#routergetputpostpatchdeletedel) + * [router.routes()](#routerroutes) + * [router.use([path], middleware)](#routerusepath-middleware) + * [router.allowedMethods([options])](#routerallowedmethodsoptions) + * [router.redirect(source, destination, [code])](#routerredirectsource-destination-code) + * [router.route(name)](#routerroutename) + * [router.url(name, params, [options])](#routerurlname-params-options) + * [router.param(param, middleware)](#routerparamparam-middleware) + * [Router.url(path, params)](#routerurlpath-params) +* [Plugin](#plugin) + * [new Plugin(options)](#new-pluginoptions) + + + +[router-verbs]: https://github.com/alexmingoia/koa-router#routergetputpostpatchdeletedel--router +[router-routes]: https://github.com/alexmingoia/koa-router#routerroutes--function +[router-use]: https://github.com/alexmingoia/koa-router#routerusepath-middleware--router +[router-allowmethods]: https://github.com/alexmingoia/koa-router#routerallowedmethodsoptions--function +[router-redirect]: https://github.com/alexmingoia/koa-router#routerredirectsource-destination-code--router +[router-route]: https://github.com/alexmingoia/koa-router#routerroutename--layer--false +[router-url]: https://github.com/alexmingoia/koa-router#routerurlname-params-options--string--error +[router-param]: https://github.com/alexmingoia/koa-router#routerparamparam-middleware--router +[Router-url]: https://github.com/alexmingoia/koa-router#routerurlpath-params--string +[oai-fields]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields-5 + +# Router + +继承自[koa-router](https://github.com/alexmingoia/koa-router),除了`prefix`选项暂时不支持外,保持其他原功能、特性、性能。在此之外增加一些新功能。 + +## new Router(options) + +* `options` {object} 路由的配置选项。有以下字段: + * `apiDoc` {string} `必须` api文档或者文档目录。当为api文档目录时,会自动加载目录内的其他文件。 + * `apiExplorerVisible` {boolean} `可选` 是否启用`api-explorer`。默认为`true`。 + * `options` {object} `可选` 插件的选项,也可以在插件使用时配置。`key`是插件的名称,`value`是插件的参数。 + +`apiDoc`描述文档可以是yaml或者json格式。当`apiDoc`是目录时,各个api文档描述目录中的内容将被合并之后加载到OpenAPI协议文档中。`/project/paths`中的内容将被加载到文档的`paths`字段下,`/project/definitions`中的内容将被加载到文档的`definitions`字段下,其他文件夹不会被加载。 + +api文档描述目录结构如下: +* `project` + * `api.yaml` + * `paths` + * `definitions` + * `parameters` + * `responses` + * `securityDefinitions` + * `security` + * `tags` + * `externalDocs` + + +如果你只想使用router的基础功能和`api-explorer`,那么你可以不使用任何插件,只需要配置`apiDoc`和`apiExplorerVisible`即可。服务的路由和业务中间件需要由你手动来绑定。代码如下: +```js +const Koa = require('koa'); +const Router = require('koa-oai-router'); + +const app = new Koa(); + +const router = new Router({ + apiDoc: './api', + apiExplorerVisible: true, +}); + +// 手动挂载/hello路由与业务中间件 +router.get('/hello', (ctx, next) => { + ctx.response.body = 'world'; +}); + +app.use(router.routes()); + +app.listen(3000); +``` + +## router.mount(Plugin) +将插件挂载到router上,先挂载的插件先被执行。如果其中一个插件未唤起next(),那么后续插件链的执行将被结束。 + +## router.get|put|post|patch|delete|del +Same as koa-router: [router.get|put|post|patch|delete|del][router-verbs] + +## router.routes() +Same as koa-router: [router.routes()][router-routes] + +## router.use([path], middleware) +Same as koa-router: [router.use([path], middleware)][router-use] + +## router.allowedMethods([options]) +Same as koa-router: [router.allowedMethods([options])][router-allowmethods] + +## router.redirect(source, destination, [code]) +Same as koa-router: [router.redirect(source, destination, [code])][router-redirect] + +## router.route(name) +Same as koa-router: [router.route(name)][router-route] + +## router.url(name, params, [options]) +Same as koa-router: [router.url(name, params, [options])][router-url] + +## router.param(param, middleware) +Same as koa-router: [router.param(param, middleware)][router-param] + +## Router.url(path, params) +Same as koa-router: [Router.url(path, params)][Router-url] + + +# Plugin +插件是可以应用在每一个接口上的koa中间。 +它的激活取决于该接口描述文档中是否包含它的`激活字段(field)`。一旦插件被激活,那么`middlewareWrapper`将在内部被调用,并传入(middlewareOpts, middlewareArgs)参数,且必须返回一个koa中间件,该中间件将被挂载到当前接口上。 + +## new Plugin(options) + +* `options` {object} 插件的配置选项。有以下字段: + * `name` {string} `必须` 插件的名称。在路由的`options`中配置插件参数时作为key。 + * `field` {string|string[]} `必须` 激活字段。当API文档中包含该字段时插件被激活。字段范围参考[Operation Object][oai-fields]。 + * `middlewareWrapper` {object} `必须` 插件逻辑模块,必须返回一个koa中间件。 + * `middlewareArgs` {object} `可选` 插件的全局选项。 + +创建一个Router的插件。 + +`middlewareWrapper`必须返回一个koa中间件,有(middlewareOpts, middlewareArgs)参数: +* `middlewareOpts` {object} 插件被激活时当前接口文档片段的信息。 + * `endpoint` {string} 接口的路径 + * `field` {string} 被激活时的关键字 + * `fieldValue` {object} 被激活时的关键字对应的数据 + * `operation` {string} 接口的方法 + * `operationValue` {object} 接口的描述信息 +* `middlewareArgs` {any} 插件的全局选项。 + +`middlewareArgs`可以在创建router时配置,本方法的配置将拥有最高优先级。 +```js +const plugin = new PluginXXX({ + name: 'pluginXXX', + field: 'parameters', + // middlewareArgs: pluginArgs, + middlewareWrapper: () => { + return (ctx, next) => {return next();}; + }, +}); + +const router = new Router({ + apiDoc: './api', + options: { + pluginXXX: pluginArgs, + } +}); + +router.mount(plugin); +``` + +`middlewareArgs`也可以在创建插件时配置,本方法的配置将拥有最低的优先级。 +```js +const plugin = new PluginXXX({ + name: 'pluginXXX', + field: 'parameters', + middlewareArgs: pluginArgs, + middlewareWrapper: () => { + return (ctx, next) => {return next();}; + }, +}); + +const router = new Router({ + apiDoc: './api', +}); + +router.mount(plugin); +``` diff --git a/docs/zh/usage-guides.md b/docs/zh/usage-guides.md new file mode 100644 index 0000000..30404ce --- /dev/null +++ b/docs/zh/usage-guides.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/images/api-explorer.png b/images/api-explorer.png deleted file mode 100644 index e379ad9..0000000 Binary files a/images/api-explorer.png and /dev/null differ