@abiee/express-open-api 中文文档教程

发布于 4年前 浏览 20 项目主页 更新于 3年前

Express OpenAPI

express 的另一个 OpenAPI 验证器。

Installation

您可以使用 npm 安装它:

npm install --save @abiee/express-open-api

或者使用 yarn

yarn add @abiee/express-open-api

Usage

您需要在某处有一个 OpenAPI 规范文件

const express = require('express');
const expressOpenAPI = require('@abiee/express-open-api');

const app = express();
const middleware = expressOpenAPI('/path/to/your/spec.yml');

app.get('/foo', middleware, (req, res) => {
  res.send({ foo: 'bar' });
});

app.get('/xyz', middleware, (req, res) => {
  res.send({ message: 'foobar' });
});

可以使用以下方式创建 valiator 中间件:

expressOpenAPI(pathToSpecFile, options);

Options

完整选项对象:

{
  allowNotDefinedPaths: false,
  allowNotDefinedResponses: false,
  validateResponses: true,
  invalidRequestHandler: (error, req, res, next) => next(), // ignore all errors
  invalidResponseHandler: (error, body, req, res) => res.status(res.statusCode).send(body), // ignore all errors
  onRequestValidationError: (error, method, endpoint) => console.log(error), // prints all errors
  onResponseValidationError: (error, method, endpoint, statusCode) => console.log(error), // prints all errors
  onMissingPath: (method, endpoint, error) => console.log(error), // prints all paths that are missed in the spec file
  onMissingResponse: (method, endpoint, statusCode, error) => console.log(error) // prints all responses without OpenAPI spec
}

allowNotDefinedPaths

默认值: false

允许或不允许在 OpenAPI 规范文件中为快速路由定义路径。

false 时,它将强制在 OpenAPI 规范文件中为快速路由定义路径。 如果您的路由在 OpenAPI 规范文件中缺少路径,那么它将返回 400 错误。

{
  "code": "ENDPOINT_NOT_DEFINED_IN_API_SPEC",
  "method": "GET",
  "endpoint": "/path/to/foo"
}

true 时,它将允许您拥有没有 OpenAPI 规范的路由。 换句话说,它将忽略 OpenAPI 规范文件中任何缺失的路径。 如果您有现成的 API 并且您希望在执行过程中逐步将路径添加到您的规范文件,这可能很有用。

allowNotDefinedResponses

默认值:false

当 express 返回响应时,允许或不在规范文件中定义响应。

false 时,它将强制在 OpenAPI 规范文件中为快速路由定义所有响应。 如果您的路线具有已定义的路线但缺少 OpenAPI 规范文件中的响应状态代码,则它将返回 501 错误。

{
  "code": "RESPONSE_NOT_DEFINED_IN_API_SPEC",
  "method": "GET",
  "endpoint": "/path/to/foo",
  "statusCode": 401
}

注意:中间件将首先查找状态代码,如果没有找到,则查找 default 响应。

validateResponses

默认值:true

是否验证响应。 当 false 时,验证器将忽略所有响应。 当 true 时,它将根据 OpenAPI 规范文件验证所有响应。 如果响应无效,则它将在定义时调用 invalidResponseHandler(),或者使用默认错误处理程序返回 501 错误。

{
  "code": "BAD_RESPONSE",
  "errors": [{
    // ... list of ajv errors
  }]
}

invalidRequestHandler

可选

当在路由请求中发现错误时,您可以覆盖验证中间件的默认行为。 定义后,将使用以下签名调用该函数:

function errorHandler(error, req, res, next)

请注意,如果您的错误处理程序出现错误,则中间件将返回 500 Internal Server Error。 在函数中,您可以定义处理错误所需的任何内容。 请注意,错误可能是这些类别中的任何一个:

  • ValidationError
  • RouteNotDefinedInOpenAPISpec
  • InvalidAPISpecFormat
  • Generic errors

有关这些错误的更多详细信息,请参见下文。 如果您没有定义错误处理程序,则默认行为如下:

ValidationError 将是 400 Bad Request 错误。 使用负载:

{
  "code": "BAD_REQUEST",
  "errors": [{
    // ... list of ajv errors
  }]
}

RouteNotDefinedInOpenAPISpec 将是 400 Bad Request 负载:

{
  "code": "ENDPOINT_NOT_DEFINED_IN_API_SPEC",
  "method": "GET|POST|DELETE|PUT|...",
  "endpont": "/path/to/endpoint"
}

InvalidAPISpecFormat 将是 500 Internal Server Error with payload:

{
  "code": "INVALID_API_SPEC_FORMAT",
  "file": "/path/to/spec.yml".
  "error": {
    // ... swagger-parser error
  }
}

发生意外错误时将出现 500 Internal Server Error with payload:

{
  "code": "INTERNAL_SERVER_ERROR",
  "error": {
    // ... serialized error to JSON
  }
}

invalidResponseHandler

Optional

当在路由响应中发现错误时,您可以覆盖验证中间件的默认行为。 定义后,将使用以下签名调用该函数:

function errorHandler(error, body, req, res)

请注意,如果您的错误处理程序出现错误,则中间件将返回 500 Internal Server Error。 在函数中,您可以定义处理错误所需的任何内容。 请注意,错误可能是这些类别中的任何一个:

  • ValidationError
  • ResponseNotDefinedInOpenAPISpec
  • InvalidAPISpecFormat
  • Generic errors

有关这些错误的更多详细信息,请参见下文。 如果您没有定义错误处理程序,则默认行为如下:

ValidationError 将是 501 Not Implemented 错误。 负载:

{
  "code": "BAD_RESPONSE",
  "errors": [{
    // ... list of ajv errors
  }]
}

ResponseNotDefinedInOpenAPISpec 将是 501 Not Implemented 负载:

{
  "code": "RESPONSE_NOT_DEFINED_IN_API_SPEC",
  "method": "GET|POST|DELETE|PUT|...",
  "endpont": "/path/to/endpoint",
  "statusCode": 200|400|401|...
}

InvalidAPISpecFormat 将是 500 Internal Server Error with payload:

{
  "code": "INVALID_API_SPEC_FORMAT",
  "file": "/path/to/spec.yml".
  "error": {
    // ... swagger-parser error
  }
}

出现意外错误将是 500 Internal Server Error with payload:

{
  "code": "INTERNAL_SERVER_ERROR",
  "error": {
    // ... serialized error to JSON
  }
}

onRequestValidationError

Optional

只要中间件在验证请求时发现错误,就会调用此函数。 您可以使用此功能记录错误或将它们发送到错误监控系统。

function onError(error, method, endpoint)

可能报告的错误:

  • ValidationError
  • RouteNotDefinedInOpenAPISpec
  • InvalidAPISpecFormat

注意:此函数抛出的任何错误都将被中间件忽略。

onResponseValidationError

可选

此函数将在中间件在验证响应时发现错误的任何时候调用。 您可以使用此功能记录错误或将它们发送到错误监控系统。

function onError(error, method, endpoint, statusCode)

可能报告的错误:

  • ValidationError
  • ResponseNotDefinedInOpenAPISpec
  • InvalidAPISpecFormat

注意:此函数抛出的任何错误都将被中间件忽略。

onMissingPath

可选

当没有为路由定义路径时将调用此函数。 这只是一个通知。 您可以使用此功能记录错误或将它们发送到错误监控系统。

function onMissingPath(method, endpoint, error)

onMissingResponse

可选

当没有为路由定义返回的响应时将调用此函数。 这只是一个通知。 您可以使用此功能记录错误或将它们发送到错误监控系统。

function onMissingResponse(method, endpoint, statusCode, error)

Errors

当验证中间件发生验证错误时,将抛出这些错误。 您可以通过以下方式导入错误:

const {
  ValidationError,
  RouteNotDefinedInOpenAPISpec,
  ResponseNotDefinedInOpenAPISpec,
  InvalidAPISpecFormat
} = require('@abiee/express-open-api/errors');

ValidationError

当 OpenAPI 规范文件中的 API 规范与给定路径中收到的请求不匹配时,就会发生此错误。 可用的公共方法是:

  • getErrors(). Return a list of errors found in the request. It validates the request body and query parameters when available. The errors has the format defined by the AJV library.

RouteNotDefinedInOpenAPISpec

allowNotDefinedPaths 设置为 false 并且请求的路由未在 OpenAPI 规范文件的路径中定义时。 可用的公共方法是:

  • getMethod(). HTTP method for the endpoint. Could be GET, POST, DELETE, PUT, etc.
  • getEndpoint(). This is the full endpoint route.

InvalidAPISpecFormat

如果 OpenAPI 规范文件没有有效的 OpenAPI 格式,将抛出此错误。 可用的公共方法有:

  • getFilePath(). The path to the main OpenAPI Spec file.
  • getError(). The error returned by swagger-parser when validating the file.

Examples

以下是一些用例,展示了如何使用验证中间件。

Custom validation responses

您可能有自己的 API 标准,而默认的服务器响应正在破坏它们。 您可以根据需要更改默认响应:

const express = require('express');
const expressOpenAPI = require('@abiee/express-open-api');
const {
  ValidationError,
  RouteNotDefinedInOpenAPISpec,
  ResponseNotDefinedInOpenAPISpec,
  InvalidAPISpecFormat
} = require('@abiee/express-open-api/errors');

const app = express();

const middleware = expressOpenAPI('/path/to/your/spec.yml', {
  invalidRequestHandler: (error, req, res, next) => {
    if (error instanceof ValidationError) {
      res.status(400).send({
        status: 10001,
        message: 'invalid request',
        errorList: error.getErrors()
      });
    } else if (error instanceof InvalidAPISpecFormat) {
      res.status(500).send({
        status: 10010,
        message: 'invalid api spec'
      });
    } else if (error instanceof RouteNotDefinedInOpenAPISpec) {
      res.status(400).send({
        status: 10012,
        message: 'invalid route'
      });
    } else {
      res.status(500).send({
        status: 10000,
        message: 'server error'
      });
    }
  },
  invalidResponseHandler: (error, body, req, res) => {
    if (error instanceof ValidationError) {
      res.status(400).send({
        status: 10002,
        message: 'invalid response',
        errorList: error.getErrors()
      });
    } else if (error instanceof InvalidAPISpecFormat) {
      res.status(500).send({
        status: 10010,
        message: 'invalid api spec'
      });
    } else if (error instanceof ResponseNotDefinedInOpenAPISpec) {
      // ignore undefined specs
      res.status(res.statusCode).send(body);
    } else {
      res.status(500).send({
        status: 10000,
        message: 'server error'
      });
    }
  }
});

app.get('/foo', middleware, (req, res) => {
  res.send({ foo: 'bar' });
});

app.get('/xyz', middleware, (req, res) => {
  res.send({ message: 'foobar' });
});

Validate against OpenAPI but do not change actual API behaviour

您可以再次监控 OpenAPI 规范与实际 API 的合规性。 这对于 production 中的合同测试很有用,不会破坏任何东西。

const express = require('express');
const expressOpenAPI = require('@abiee/express-open-api');
const Sentry = require('@sentry/node');
const {
  ValidationError,
  RouteNotDefinedInOpenAPISpec,
  ResponseNotDefinedInOpenAPISpec,
  InvalidAPISpecFormat
} = require('@abiee/express-open-api/errors');

Sentry.init({ /* ... */ });

const app = express();

const middleware = expressOpenAPI('/path/to/your/spec.yml', {
  allowNotDefinedPaths: true,
  allowNotDefinedResponses: true,
  invalidRequestHandler: (error, req, res, next) => {
    if (error instanceof InvalidAPISpecFormat) {
      return res.status(500).send({ code: 'INTERNAL_SERVER_ERROR' });
    }

    next(); // ignore all validation errors
  },
  invalidResponseHandler: (error, body, req, res) => {
    res.status(res.statusCode).send(body); // ignore all validation errors
  },
  onRequestValidationError: (error, method, endpoint) => {
    if (error instanceof ValidationError) {
      Sentry.captureException(error);
    }
  },
  onResponseValidationError: (error, method, endpoint, statusCode) => {
    if (error instanceof ValidationError) {
      Sentry.captureException(error);
    }
  }
});

app.get('/foo', middleware, (req, res) => {
  res.send({ foo: 'bar' });
});

app.get('/xyz', middleware, (req, res) => {
  res.send({ message: 'foobar' });
});

Express OpenAPI

Another OpenAPI Validator for express.

Installation

You can install this with npm:

npm install --save @abiee/express-open-api

Or with yarn:

yarn add @abiee/express-open-api

Usage

You need to have an OpenAPI Spec file somewhere

const express = require('express');
const expressOpenAPI = require('@abiee/express-open-api');

const app = express();
const middleware = expressOpenAPI('/path/to/your/spec.yml');

app.get('/foo', middleware, (req, res) => {
  res.send({ foo: 'bar' });
});

app.get('/xyz', middleware, (req, res) => {
  res.send({ message: 'foobar' });
});

The valiator middleware can be created with:

expressOpenAPI(pathToSpecFile, options);

Options

Full options object:

{
  allowNotDefinedPaths: false,
  allowNotDefinedResponses: false,
  validateResponses: true,
  invalidRequestHandler: (error, req, res, next) => next(), // ignore all errors
  invalidResponseHandler: (error, body, req, res) => res.status(res.statusCode).send(body), // ignore all errors
  onRequestValidationError: (error, method, endpoint) => console.log(error), // prints all errors
  onResponseValidationError: (error, method, endpoint, statusCode) => console.log(error), // prints all errors
  onMissingPath: (method, endpoint, error) => console.log(error), // prints all paths that are missed in the spec file
  onMissingResponse: (method, endpoint, statusCode, error) => console.log(error) // prints all responses without OpenAPI spec
}

allowNotDefinedPaths

Default: false

Allow or not to have not defined paths in the OpenAPI spec file for express routes.

When false it will enforce to have the path defined in the OpenAPI spec files for express routes. If you have a route with a missing path in the OpenAPI spec files then it will return a 400 error.

{
  "code": "ENDPOINT_NOT_DEFINED_IN_API_SPEC",
  "method": "GET",
  "endpoint": "/path/to/foo"
}

When true it will allow you to have routes without an OpenAPI spec. In other words, it will ignore any missing path in the OpenAPI spec files. This could be useful if you have en existent API and you want to incrementally add paths to your spec files as you go.

allowNotDefinedResponses

Default: false

Allow or no to have not defined respones in the spec file when express returns a response.

When false it will enforce to have all responses defined in the OpenAPI spec files for express routes. If you have a route with a defined route but missing response status code in the OpenAPI spec files then it will return a 501 error.

{
  "code": "RESPONSE_NOT_DEFINED_IN_API_SPEC",
  "method": "GET",
  "endpoint": "/path/to/foo",
  "statusCode": 401
}

Note: the middleware will look uf for the status code first, if not found then will look up for a default response.

validateResponses

Default: true

Validate responses or not. When false all respones will be ignored by the validator. When true it will validate all respones against the OpenAPI spec file. If a response is not valid then it will call invalidResponseHandler() when defined, or will use the default error handler returning a 501 error.

{
  "code": "BAD_RESPONSE",
  "errors": [{
    // ... list of ajv errors
  }]
}

invalidRequestHandler

Optional

You may override the default behaviour of the validation middleware when an error is found in a request to a route. When defined, the function is called with the following signature:

function errorHandler(error, req, res, next)

Please note that if you error handler has an error then the middleware will return a 500 Internal Server Error. In the function you can define anything you need to handle errors. Please be aware that error could be any of these classes:

  • ValidationError
  • RouteNotDefinedInOpenAPISpec
  • InvalidAPISpecFormat
  • Generic errors

See below for more details about these errors. If you do not define an error handler the default behaviour is as follows:

ValidationError will be a 400 Bad Request error. With payload:

{
  "code": "BAD_REQUEST",
  "errors": [{
    // ... list of ajv errors
  }]
}

RouteNotDefinedInOpenAPISpec will be a 400 Bad Request error with payload:

{
  "code": "ENDPOINT_NOT_DEFINED_IN_API_SPEC",
  "method": "GET|POST|DELETE|PUT|...",
  "endpont": "/path/to/endpoint"
}

InvalidAPISpecFormat will be a 500 Internal Server Error with payload:

{
  "code": "INVALID_API_SPEC_FORMAT",
  "file": "/path/to/spec.yml".
  "error": {
    // ... swagger-parser error
  }
}

On unexpcted errors will be a 500 Internal Server Error with payload:

{
  "code": "INTERNAL_SERVER_ERROR",
  "error": {
    // ... serialized error to JSON
  }
}

invalidResponseHandler

Optional

You may override the default behaviour of the validation middleware when an error is found in the response of a route. When defined, the function is called with the following signature:

function errorHandler(error, body, req, res)

Please note that if you error handler has an error then the middleware will return a 500 Internal Server Error. In the function you can define anything you need to handle errors. Please be aware that error could be any of these classes:

  • ValidationError
  • ResponseNotDefinedInOpenAPISpec
  • InvalidAPISpecFormat
  • Generic errors

See below for more details about these errors. If you do not define an error handler the default behaviour is as follows:

ValidationError will be a 501 Not Implemented error. With payload:

{
  "code": "BAD_RESPONSE",
  "errors": [{
    // ... list of ajv errors
  }]
}

ResponseNotDefinedInOpenAPISpec will be a 501 Not Implemented error with payload:

{
  "code": "RESPONSE_NOT_DEFINED_IN_API_SPEC",
  "method": "GET|POST|DELETE|PUT|...",
  "endpont": "/path/to/endpoint",
  "statusCode": 200|400|401|...
}

InvalidAPISpecFormat will be a 500 Internal Server Error with payload:

{
  "code": "INVALID_API_SPEC_FORMAT",
  "file": "/path/to/spec.yml".
  "error": {
    // ... swagger-parser error
  }
}

On unexpcted errors will be a 500 Internal Server Error with payload:

{
  "code": "INTERNAL_SERVER_ERROR",
  "error": {
    // ... serialized error to JSON
  }
}

onRequestValidationError

Optional

This function will be called anytime the middleware finds an error while validating request. You can use this function to log errors or send them to a error monitor system.

function onError(error, method, endpoint)

Errors that could be reported:

  • ValidationError
  • RouteNotDefinedInOpenAPISpec
  • InvalidAPISpecFormat

NOTE: Any error throwed by this function will be ignored by the middleware.

onResponseValidationError

Optional

This function will be called anytime the middleware finds an error while validating the response. You can use this function to log errors or send them to a error monitor system.

function onError(error, method, endpoint, statusCode)

Errors that could be reported:

  • ValidationError
  • ResponseNotDefinedInOpenAPISpec
  • InvalidAPISpecFormat

NOTE: Any error throwed by this function will be ignored by the middleware.

onMissingPath

Optional

This function will be called when a path is not defined for a route. This is just a notification. You can use this function to log errors or send them to a error monitor system.

function onMissingPath(method, endpoint, error)

onMissingResponse

Optional

This function will be called when a returned response is not defined for a route. This is just a notification. You can use this function to log errors or send them to a error monitor system.

function onMissingResponse(method, endpoint, statusCode, error)

Errors

Those errors will be throwed when a validation error occours in the validation middleware. You can import errors with:

const {
  ValidationError,
  RouteNotDefinedInOpenAPISpec,
  ResponseNotDefinedInOpenAPISpec,
  InvalidAPISpecFormat
} = require('@abiee/express-open-api/errors');

ValidationError

This errors happens when the API Specification in the OpenAPI Spec files does not match with the requested received in a given path. The available public methods are:

  • getErrors(). Return a list of errors found in the request. It validates the request body and query parameters when available. The errors has the format defined by the AJV library.

RouteNotDefinedInOpenAPISpec

When allowNotDefinedPaths is set to false and the requested route is not defined in the paths of the OpenAPI spec files. The available public methods are:

  • getMethod(). HTTP method for the endpoint. Could be GET, POST, DELETE, PUT, etc.
  • getEndpoint(). This is the full endpoint route.

InvalidAPISpecFormat

If the OpenAPI Spec files has not a valid OpenAPI format this error will be throwed. The available public method are:

  • getFilePath(). The path to the main OpenAPI Spec file.
  • getError(). The error returned by swagger-parser when validating the file.

Examples

Here are some use cases that shows how the validation middleware can be used.

Custom validation responses

You may have your own API standards and the default server responses are breaking them. You can change the default responses as you need:

const express = require('express');
const expressOpenAPI = require('@abiee/express-open-api');
const {
  ValidationError,
  RouteNotDefinedInOpenAPISpec,
  ResponseNotDefinedInOpenAPISpec,
  InvalidAPISpecFormat
} = require('@abiee/express-open-api/errors');

const app = express();

const middleware = expressOpenAPI('/path/to/your/spec.yml', {
  invalidRequestHandler: (error, req, res, next) => {
    if (error instanceof ValidationError) {
      res.status(400).send({
        status: 10001,
        message: 'invalid request',
        errorList: error.getErrors()
      });
    } else if (error instanceof InvalidAPISpecFormat) {
      res.status(500).send({
        status: 10010,
        message: 'invalid api spec'
      });
    } else if (error instanceof RouteNotDefinedInOpenAPISpec) {
      res.status(400).send({
        status: 10012,
        message: 'invalid route'
      });
    } else {
      res.status(500).send({
        status: 10000,
        message: 'server error'
      });
    }
  },
  invalidResponseHandler: (error, body, req, res) => {
    if (error instanceof ValidationError) {
      res.status(400).send({
        status: 10002,
        message: 'invalid response',
        errorList: error.getErrors()
      });
    } else if (error instanceof InvalidAPISpecFormat) {
      res.status(500).send({
        status: 10010,
        message: 'invalid api spec'
      });
    } else if (error instanceof ResponseNotDefinedInOpenAPISpec) {
      // ignore undefined specs
      res.status(res.statusCode).send(body);
    } else {
      res.status(500).send({
        status: 10000,
        message: 'server error'
      });
    }
  }
});

app.get('/foo', middleware, (req, res) => {
  res.send({ foo: 'bar' });
});

app.get('/xyz', middleware, (req, res) => {
  res.send({ message: 'foobar' });
});

Validate against OpenAPI but do not change actual API behaviour

You may just monitor the compliance of your OpenAPI Specification agains the actual API. This could be useful for contract testing in production without break anything.

const express = require('express');
const expressOpenAPI = require('@abiee/express-open-api');
const Sentry = require('@sentry/node');
const {
  ValidationError,
  RouteNotDefinedInOpenAPISpec,
  ResponseNotDefinedInOpenAPISpec,
  InvalidAPISpecFormat
} = require('@abiee/express-open-api/errors');

Sentry.init({ /* ... */ });

const app = express();

const middleware = expressOpenAPI('/path/to/your/spec.yml', {
  allowNotDefinedPaths: true,
  allowNotDefinedResponses: true,
  invalidRequestHandler: (error, req, res, next) => {
    if (error instanceof InvalidAPISpecFormat) {
      return res.status(500).send({ code: 'INTERNAL_SERVER_ERROR' });
    }

    next(); // ignore all validation errors
  },
  invalidResponseHandler: (error, body, req, res) => {
    res.status(res.statusCode).send(body); // ignore all validation errors
  },
  onRequestValidationError: (error, method, endpoint) => {
    if (error instanceof ValidationError) {
      Sentry.captureException(error);
    }
  },
  onResponseValidationError: (error, method, endpoint, statusCode) => {
    if (error instanceof ValidationError) {
      Sentry.captureException(error);
    }
  }
});

app.get('/foo', middleware, (req, res) => {
  res.send({ foo: 'bar' });
});

app.get('/xyz', middleware, (req, res) => {
  res.send({ message: 'foobar' });
});
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文