node package manager
Easy sharing. Manage teams and permissions with one click. Create a free org »

koa-oai-router

Koa-OAI-Router

License NPM Version Node Version Build Status Test Coverage Downloads Dependency Status

NPM

中文 English

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.

I truly hope that this library can help those who are in the same trouble. Happy coding.

BTW,PR & Issue & Star are welcome! : )



Notice:Testing stage,Production not recommend!!!

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):

npm install koa-oai-router@next --save

For koa@<2.x:

Not Support Yet!

Quick Start

Creating API doc

If you not know how to do this. please read OpenAPI first.

# 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-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-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

Creating controller

do your staff code

// 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
};

Creating koa app

// app.js 
 
import Koa from ('koa');
import bodyParser from ('koa-bodyparser');
import Router from ('koa-oai-router');
 
const app = new Koa();
const server = app.listen(9000);
 
app.use(bodyParser());
 
// 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
};
 
var router = new Router(opt);
// mount routes in api doc 
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

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.

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.

import Koa from ('koa');
import bodyParser from ('koa-bodyparser');
import Router from ('koa-oai-router');
 
const app = new Koa();
const server= app.listen(9000);
 
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';
    }
  }
};
 
const router = new Router(opt);
app.use(router.routes());
app.use(router.apiExplorer());

errorHandler

function optional default error handler

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. 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

Contrller

koa-oai-router enlarges OpenAPI, now we will recognize x-controller keyword in all method.

x-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

paths:
  /people:
    get:
      tags:
        - People
      description: find a people by name or mobile
      x-controller:
        file: acl
          handler: isAdmin
        file: people
          handler: get

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.

  • support common function
  • support async function
  • support generator function

Parameter validate

Validation is based on JSON-Schema Draft 4, 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

OpenAPI parameter object

header

Validate the header of request.

paths:
  /users:
    get:
      summary: List all users
      parameters:
        name: token
          in: header
          description: token to be passed as a header
          required: true
          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}".

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.

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.

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)

TODO

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.

swagger: '2.0'
info:
  version: 1.0.0
  title: koa-oai-router
consumes:
  - application/json
produces:
  - application/json
basePath: /api
paths:
  /user:
    get:
      x-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

When page is not inputed, the api will send HTTP 400 with the response body handled by error handler.

{
    "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": "...."
    }
}

Plan

  • Support OpenAPI/Swagger1.x
  • Support OpenAPI/Swagger2.0 Security keyword
  • Support Response validate
  • Built-in more format validation(e-mail, ip, Tel)
  • More unit test
  • Benchmark