uniquejava / blog

My notes regarding the vibrating frontend :boom and the plain old java :rofl.
Creative Commons Zero v1.0 Universal
11 stars 5 forks source link

swagger-node(swagger and node.js) #241

Open uniquejava opened 6 years ago

uniquejava commented 6 years ago

项目地址: https://github.com/swagger-api/swagger-node 官方文档: https://github.com/swagger-api/swagger-node/tree/master/docs 非常重要的官方文档(如: default.yaml的配置) https://github.com/apigee-127/swagger-node-runner/releases/tag/v0.6.0

必须要配置_swagger_params_parser不然连req.body都取不到.

npm i -g swagger
swagger project create hello-world
swagger project start
swagger project edit

但是这个swagger project edit打开的界面特别LOW且buggy, 我是直接到这里去编辑yaml文件: http://editor.swagger.io

使用swagger命令生成的项目结构: image

测试: http://127.0.0.1:10010/hello?name=Scott

内置的swagger-express-mw还是0.1.0版本, editor界面十分之丑陋.

可以将其升级到swagger-express-mw到0.7.0: 详见: https://github.com/swagger-api/swagger-node/issues/551

0.7.0不再自带swagger-tools需要单独安装

npm i swagger-tools

在app.js中

const SwaggerUi = require("swagger-tools/middleware/swagger-ui");

swaggerExpress.register(app);
let defaultOptions = {
  apiDocs: "/xxxxx/api-docs",
  swaggerUi: "/xxxxx/docs"
};

if (isDev) {
  app.use(SwaggerUi(swaggerExpress.runner.swagger, defaultOptions));
  let swaggerUiURL = `http://localhost:${port}${defaultOptions.swaggerUi}`;
  logger.info(`Swagger UI is available at:\n${swaggerUiURL}`);
}

OpenAPI specification(v2 / v3) https://swagger.io/resources/open-api/

See swagger and OpenAPI in general https://github.com/uniquejava/blog/issues/167

swagger project edit会打开chrome browser在线编辑yaml文件, 这个文件和项目中的api/swagger/swagger.yaml是同步变化的.

x-swagger-router-controller指定使用api/controllers/下的哪个文件处理请求 operationId 指定应该调用controller中的哪个方法

https://stackoverflow.com/questions/48111459/how-to-define-a-property-that-can-be-string-or-null-in-openapi-swagger

uniquejava commented 6 years ago

怎么在mongodb初始化结束后再启动test case

搭配使用app.emit('ready')before(()=>app.on('ready', done)) https://stackoverflow.com/questions/18941736/ensuring-express-app-is-running-before-each-mocha-test

为什么在POST body为空时还需要指定content-type为application/json?

原因见: https://github.com/swagger-api/swagger-ui/issues/1576 解决办法, 修改swagger.yaml对consumes部分的定义:

consumes:
  - application/json
  - application/octet-stream

这样测试POST请求时如果body为空, 可以不必指定content-type: application/json.

swagger-node怎么定义securityHandlers

app.js:

var config = {
  appRoot: __dirname, // required config
  swaggerSecurityHandlers: {
    api_key: function (req, authOrSecDef, scopesOrApiKey, cb) {
      // your security code
      if ('1234' === scopesOrApiKey) {
        cb(null);
      } else {
        cb(new Error('access denied!'));
      }
    }
  }
};

api/swagger/swagger.yaml:

securityDefinitions:
  api_key:
    type: apiKey
    in: query
    name: api_key
paths:
  /hello:
    get:
      security:
        - api_key: [ ]

感谢: https://github.com/swagger-api/swagger-node/issues/228#issuecomment-163805253

怎么修改securityHandler返回的statusCode

var err = new Error('Failed to authenticate using bearer token');
err['statusCode'] = 403; // custom error code
callback(err);

感谢: https://github.com/apigee-127/swagger-tools/issues/203#issuecomment-246210465

还有这里!! https://github.com/swagger-api/swagger-node/issues/228

异常处理

如果想在app.js中添加自己的global error handler

// error handler
const errorHandler = (err, req, res, next) => {
  logger.error("caught by global error handler...");

  logger.error(err);

  let code = err.code || "server_error";
  let message = err.message;
  let statusCode = err.statusCode || 500;

  res.status(statusCode);
  res.json({ code, message, statusCode });
};

就是让next(error)能走到app.js、就得在default.yaml中注释掉这行 - onError: json_error_handler

    # pipe for all swagger-node controllers
    swagger_controllers:
      # - onError: json_error_handler
      - cors
      - _swagger_params_parser
      - swagger_security
      - _swagger_validate
      - express_compatibility
      - _router

一下子, 感觉空气好多了. 参考: No clear error handling documentation https://github.com/swagger-api/swagger-node/issues/410

uniquejava commented 6 years ago

格式问题

https://stackoverflow.com/questions/45549663/swagger-editor-shows-the-schema-error-should-not-have-additional-properties-e

https://stackoverflow.com/questions/31033394/swagger-editor-multiple-parameters-in-body

https://swagger.io/docs/specification/2-0/describing-request-body/

关于body要说的

  1. body的类型必定是object,即使body中只包含一个字段.因为我们统一了content-type为applicaton/json, 只有object和json能对应上(不可以是string)
  2. 基本上name也写成body, 即in: body, name: body, 这样方便在swagger中查看,换成其它的name既不统一,也不便于查看.

      parameters:
        - in: body
          name: client_id
          description: client id(speaker or web)
          required: true
          type: string

      parameters:
        - in: body
          name: client_id
          description: client id(speaker or web)
          required: true
          schema:
            type: string

你至多只能传一个body参数. 见: https://stackoverflow.com/questions/31033394/swagger-editor-multiple-parameters-in-body

paths:
  # This is a path endpoint. Change it.
  /tasks:
    post:
      description: |
        Add 'Task' object.
      parameters:
        - name: task 
          in: body
          description: task object
          required: true
          schema:
            $ref: '#/definitions/Task'

再一例

      parameters:
        - in: body
          name: user
          description: The user to create.
          schema:
            type: object
            required:
              - userName
            properties:
              userName:
                type: string
              firstName:
                type: string
              lastName:
                type: string
uniquejava commented 5 years ago

swagger-node 内置了multer做为文件上传组件.

upload single file

swagger-node完全支持单文件上传

相关的swagger文档: https://swagger.io/docs/specification/2-0/file-upload/

需要在app.js中对multer进行配置:

    let upload = multer({
      storage: multer.memoryStorage(),
      limits: {
        fileSize: 5 * 1024 * 1024
      }
    });

    app.use(upload.fields([{ name: "myfile" }]));

swagger.yaml

      consumes:
        - multipart/form-data
      parameters:
        - name: client_id
          in: query
          description: client id
          type: string
          required: true
        - name: first_name
          in: formData
          type: string
          required: true
        - name: last_name
          in: formData
          type: string
          required: true
        - name: email
          in: formData
          type: string
          required: true
        - name: myfile
          in: formData
          type: file
          # items:
          #   type: string
          #   format: binary
          required: true

upload multiple files

swagger-node不支持多文件上传, 不过有一个PR: https://github.com/apigee-127/swagger-tools/pull/550, 好用但未被合并.

        - name: myfile
          in: formData
          type: array
          items:
            type: string
            format: binary
          required: true

final solution

        - name: myfile
          in: formData
          type: file
          items:
            type: string
            format: binary
          required: true