使用 API-First 方法构建 RestfulAPI(一)

使用 API-First 方法构建 RestfulAPI(一)
原文标题:Designing Restful APIs using an API-First Approach
原文链接:https://dev.to/ntakashi/designing-restful-apis-using-an-api-first-approach-23e2
作者:Nicolas Takashi


我使用 Restful API 已经有一段时间了,今天我将向大家展示如何使用 API-First 方法和使用 OpenApi 规范来构建 API。

首先,如果你不知道什么是 API-First ,可以先通过看看这篇文章《API 优先、API 设计优先和代码优先》,让自己对 API-First 有初步的认识。

📋 基础准备

在开始动手之前,让我们做好准备并了解将要开发的用例。

工具

如果你希望复现本文使用的示例,你需要准备好这些工具:

  • NodeJS
  • OpenAPI 规范
  • 文本编辑器(我使用的是 VSCode)
  • 命令行

用例

为了易于理解,我们将使用 Todo List App,这是软件开发社区里一个非常普遍的方法。

免责声明

为了让大家更容易阅读 gist 文件,我将会省略一些不重要的信息。

🙌 开始编写

现在你已经拥有了全部所需的环境,让我们正式开始吧!

第一步是为 OpenAPI 规范创建入口点文件并向该文件添加一些内容。

openapi: 3.0.0
info:
  title: Todo App API
  description: Todo App API.
  version: v1
  contact:
    email: 'nicolas.tcs@hotmail.com'
    name: 'Nicolas Takashi'
paths:
#... there more content here.

上面的文件是 OpenAPI 文档的一个非常简单的示例,只是为了向你介绍这个概念。OpenAPI 的编写结构非常清晰易懂,但如果你还不知道它是如何工作的,我建议你可以先阅读官方文档

编写 Path 对象

Path 对象包含每个端点及其操作的相对路径,让我们添加一个名为 tasks.yaml 的文件,内容如下:

get:
  operationId: get-tasks
  summary: Returns a paged list of tasks.
  description: Returns a paged list of active tasks
  tags:
    - Tasks
  parameters:
    - $ref: '../../parameters/page-parameters.yaml#/components/parameters/page'
    - $ref: '../../parameters/page-parameters.yaml#/components/parameters/pageSize'
  responses:
    '200':
      description: Success
      content:
        application/json:
          schema:
            $ref: '../../schemas/pagedTask.yaml#/components/schemas/PagedTask'
post:
  operationId: create-task
  summary: Create a task
  description: Create a new task
  tags:
    - Tasks
  requestBody:
    required: true
    content:
      application/json:
        schema:
          $ref: '../../schemas/task.yaml#/components/schemas/Task'
  responses:
    '201':
      description: Created
      headers:
        Location:
          description: 'Location of the created task /tasks/{id}'
          schema:
            type: string

你可以看到上面的代码中,添加了两个操作,这将使 Todo List API 能够创建任务并获取任务的分页列表。

现在我们可以添加操作使 API 能够删除任务、查找特定任务和更新任务,为此我们必须创建一个名为的新文件tasks-with-id.yaml并添加以下内容:

get:
  operationId: get-task
  summary: Get task by id
  description: Return a task
  tags:
    - Tasks
  parameters:
    - in: path
      name: id
      description: Task id
      required: true
      schema:
        type: string
        format: uuid
  responses:
    '200':
      description: Success
      content:
        application/json:
          schema:
            $ref: '../../schemas/task.yaml#/components/schemas/Task'
put:
  operationId: update-task
  summary: Update a task
  description: Update a task
  tags:
    - Tasks
  parameters:
    - in: path
      name: id
      description: Task id
      required: true
      schema:
        type: string
        format: uuid
  requestBody:
    required: true
    content:
      application/json:
        schema:
          $ref: '../../schemas/task.yaml#/components/schemas/Task'
  responses:
    '202':
      description: No Content
delete:
  operationId: delete-task
  summary: Delete a task
  description: Delete a task
  tags:
    - Tasks
  parameters:
    - in: path
      name: id
      description: Task id
      required: true
      schema:
        type: string
        format: uuid
  responses:
    '202':
      description: No content

使用引用

在软件开发中经常需要共享代码,而在我们设计 API 时也会发生同样的情况。遵循 OpenAPI 规范使我们能够跨 OpenAPI 文档并重新利用公共对象。

使用$ref符号,你可以添加对 API 的本地或远程引用(References),比如你在上面的示例中所见的代码。如果你想更好地了解如何使用 References 以及可以在什么地方使用它,请查看官方文档

编写 Schema 对象

我们正在使用一个名为 Task 的架构组件,该架构在整个 API 中用于表示资源任务,该架构示例如下:

components:
  schemas:
    Task:
      type: object
      required:
        - name
        - id
      properties:
        id:
          description: Task unique identifier
          type: string
          format: uuid
          readOnly: true
        name:
          description: Task name
          type: string
          example: Todo Service

通过上面的代码,我们可以在所有 API 中重新利用 Task 模式并避免代码重复。

编写 Parameter 对象

就像 Schemas 一样,我们可以对参数(Parameters)做同样的事情,如果有跨 API 共享的参数,我们可以引用本地或远程文件,这里我们将创建两个参数来表示有关页面及其大小的信息:

components:
  parameters:
    page:
      in: query
      description: Desired page
      name: page
      schema:
        type: integer
        format: int32
        default: 1
        minimum: 1
    pageSize:
      in: query
      description: Desired quantity of itens per page
      name: pageSize
      schema:
        type: integer
        format: int32
        default: 10
        minimum: 10
        maximum: 100

最终的 API 入口点

看完这些文件的单独示例之后,让我们看看把这些示例连起来用的效果是怎样的:

openapi: 3.0.0
info:
  title: Todo App API
  description: Todo App API.
  version: v1
  contact:
    email: 'nicolas.tcs@hotmail.com'
    name: 'Nicolas Takashi'
tags:
  - name: Tasks
paths:
  '/tasks':
    $ref: './components/paths/tasks/task.yaml'
  '/tasks/{id}':
    $ref: './components/paths/tasks/task-by-id.yaml'
components:
  schemas:
    Task:
      $ref: 'components/schemas/task.yaml#/components/schemas/Task'
    PagedTask:
      $ref: 'components/schemas/pagedTask.yaml#/components/schemas/PagedTask'

我们设计了一个 Todo List API,接下来优化一下 API 设计,如果你像我一样使用 Visual Studio ,你可以安装一个名为 Swagger View 的扩展,这样你就可以渲染出像下图一样的效果:

swagger 视图看起来还不错,每个客户都可以通过 Swagger-UI 探索你的 API。

📦 打包 OpenAPI 文档

在开始使用 lint 和 OpenAPI 文档交互以及为我们的客户创建模拟服务器和 SDK 之前,我们必现打包 API 才能开启机器读取和交互。

为了在设计过程中帮助你避免重复和增强代码重用,你可以将 OpenAPI 文档拆分为多个文件并在之后引用这些文件。但这不是有效的 OpenAPI 文档,现在,我们将了解如何使用 swagger-cli 将许多文档打包到一个文档中。 安装swagger-cli非常简单,只需要运行下面的命令就可以了:

// using npm
npm install swagger-cli
// using yarn
yarn add swagger-cli

之后,你只需要运行下面的 bundle 命令:

swagger-cli bundle api.yaml -o ./bin/api.yaml -t yaml

完成后,你已经将 API 打包到一个文件中了,现在你可以检查该文件以确保遵循了 Restful 规范。

📐 Restful 规范

当我们设计 API 时,有一件非常重要的事情就是定义规范

软件社区提供了很多设计 RestfulAPI 的规范,但在很多情况下,这些规范不符合你的业务需求,你需要创建自己的规范。

比定义规范更重要的是确保你的 API 遵循这些规范,例如,确保每个请求都有 「200 响应」。

但是我们知道,如果不使用工具来完成这项工作是很难的,所以让我向你介绍这款好工具,并在这项工作中为你提供支持。

使用 spectral 验证 OpenAPI 文档

你很难通过手动的方式去检查你的 API 是否按照贵公司建议的规范进行设计。因此,我们可以使用像 Spectral 这样的工具来帮助我们创建一个自动化流程来完成这项工作。Spectral 是一个开源项目,它的工作方式类似于 OpenAPI 文档的 linter,并且有很多规则来检查是否使用通用的规范来开发 RestfulAPI。要使用 spectral 非常简单,你只需要使用下面的命令安装 node package:

// using npm
npm install @stoplight/spectral
// using yarn
yarn add @stoplight/spectral

在执行命令 lint 并检查 API 是否符合规范之前,你需要像之前提到的那样打包 API,之后只需运行下面的命令。

spectral lint ./bin/api.yaml --ignore-unknown-format

之后,你可以根据输出信息来判断是否有发生错误,如下图所示。

  • 光谱成功输出
  • 频谱误差输出

如果你想了解 spectral 是如何工作的,lint 有哪些可用选项,以及如何创建自己的规则或忽略现有规则,我建议你访问官方文档,里面有很好的例子说明如何做到这一点。

或者你也可以使用 Apifox 导出标准的 OpenAPI 文档,帮助你便捷快速定位错误问题。

结论

这篇文章背后的想法只是展示如何使用 API-First 方法和 OpenAPI 规范开始设计 API。在下一篇文章中,我们将讨论模拟服务器和 SDK,以及我们如何利用 OpenAPI 来帮助改进开发过程。


本系列共有三篇,欢迎阅读其他文章:

订阅
qrcode

订阅

随时随地获取 Apifox 最新动态