OpenAPI Specification 系列笔记 I

发布于:2025-09-02 ⋅ 阅读:(20) ⋅ 点赞:(0)

OpenAPI Specification 系列笔记 I

上个月入了一个新的项目,所以一些学习的进度之类的都被打乱了,可能最近这几个月都会以熟悉新工具作为主要的学习目标,眼下过一遍 swagger/OpenAPI 的一些内容

之前的话其实或多或少的也会接触一些 swagger 的部分,不过主要都是通过 UI 了解一下已经实现的 endpoint——其实就是基于 code first,然后扫描 endpoint 生成对应 UI 的实现。所以我其实没有手写过对应的 specs,只是大概对 specs 有一定的了解

关于具体的 spec,有一个 **OpenAPI Map,**这个网站是一个比较好用的可视化工具,可以具体看到每个 section 下面包含合法的属性

如果想看参考的话,GH 的链接如下:

https://github.com/GoldenaArcher/open-api-3.x-study

Specs

完整的 **OpenAPI Specification,**即官网地址在这: OpenAPI Specification,学习档案参考的主要是 3.0 的内容,目前我看到的大部分工具,更新比较快的对 3.1 的支持是 beta,更新比较慢的却是不支持的。我个人建议先看一下自己要用的工具,如果能用更新比较快/主流的工具,用 3.1 是未来的趋向

用 OpenAPI Spec 最大的原因就在于,可以比较直观地观测到 API 所有信息,下面两个截图展示了 endpoint、params 和 body:

在这里插入图片描述

在这里插入图片描述

API Specs 的优点

  1. 容易理解
  2. 可以生成 server/client 代码,同时进行数据校验
  3. mock 服务端去返回案例 responses
  4. 是一个广泛接受的标准

swagger & openapi

Swagger 起初是一个简单的开源规范(open source specification),包含 Swagger UISwagger EditorSwagger Codegen。不过在 2015 年,Swagger 被 SmartBear 收购,并将规范更名为 OpenAPI Specification,但仍保留了 Swagger 这个商标/名称

目前,Swagger 指的是一系列工具,而 OpenAPI 则专指这一套规范

swagger 工具

下面两个截图都是在 cloud 截图的:

在这里插入图片描述

在这里插入图片描述

可以看到,主流的开源工具还是只有 Swagger UISwagger EditorSwagger Codegen。Hub 是一个付费的支持,我记得的功能是集成了所有的免费功能,然后再提供了一些文档的生成管理共享等

use open api

code first approach

Swagger Hub 可以通过这个链接玩一下:https://swagger.io/tools/swaggerhub-explore/,这种方法大体就是ping一下对应的endpoint,然后swagger hub 可以自动生成对应的 request 和 response,如下面几个案例,通过 ping https://swapi.dev/https://reqres.in/https://dummyjson.com/ 等其他几个链接生成的文档:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

如果没办法查看 owner,登陆 https://app.swaggerhub.com/welcome 去验证一下是不是登陆了,成功登陆的话是可以查看文档的:

在这里插入图片描述

在这里插入图片描述

使用 swagger hub 去生成对应的文档会有几个问题:

  • id 是 hard coded
  • 可能会缺乏对应的 fields/parameters
    比如说 post 请求中的 input,一些 query parameters 等,毕竟 swagger hub 不可能穷举所有有可能的 path 去测试,这种情况下使用的 URL 中没有对应的 parameters,swagger hub 就不会生成对应的参数
  • 如果 API 不是公网可访问,那么 swagger hub 就无法 ping 到
  • 需要验证的时候,会需要手动配置对应的登陆参数

code first 这种比较适合对代码没有直接访问权限,但是需要生成对应文档的团队——有可能对接的 vendor 没有文档,所以需要生成文档供自己团队使用;或者是老项目没有文档,但是使用的框架也不支持用其他的插件生成对应的 specs

design first approach

如果手上没有现成的代码,需要生成对应的 specs 让不同的团队 review,那么 design first 是一个很好的方法。design first 可以生成不同语言的模板代码,缺点就在于需要手动写所有的定义

swagger 本身是支持 yaml 和 json 两种格式的,不过我在后面的文档里会用 yaml——一方面教程用的是 yaml,另外一方面我发现使用 yaml 却是比 json 方便一些,也短一些

如果想把 json 转 yaml,或者 yaml 转 json,可以找一些网站实现对应的功能,如:

在这里插入图片描述

最简 OpenAI specification

这三个是生成文档所需的最少 fields:

# the version of the OAS of this documentation
openapi: 3.1.0
# provide a general information about the API, only 2 mandatory fields are included
info:
  # human readable description of the project
  title: A minimal OpenAPI document
  # version of the project
  version: 0.0.1
paths: {} # no endpoints defined, empty array

效果如下:

⚠️:刚开始的时候我是在网页里面实现的,后来发现 vscode 里的 swagger 支持也蛮好的,所以后期会换到 vscode

info

info 如其名,用来描述整个 API 的 metadata,其中 titleversion 是必选项:

info:
  title: EazyShop Products APIs Definition
  version: 0.0.1
  # below are optional fields
  # summary is only supported after version 3.1.0, which is supported with latest swagger editor
  summary: a summary
  description: a detailed description of the API
  # a link point to the terms of serfice for the API, must be the format of a URL
  termsOfService: "http://example.com/terms/"
  # contact information for the exposed API
  contact:
    name: "API Support"
    url: "http://www.example.com/support"
    email: "support@example.com"
  # licence information for the exposed API
  license:
    name: "Apache 2.0"
    url: "https://www.apache.org/licenses/LICENSE-2.0.html"

在这里插入图片描述

servers

这是一个可选项,用来描述当前服务器。一般来说,如果想直接用 swagger 来调用 crul 指令,可以将对应 server 信息放上去,然后切换环境调用

具体的调用方式有两种:

  1. 简单版

    servers:
      - url: "https://api.example.com/v1"
        description: "Production server"
      - url: "https://staging-api.example.com/v1"
        description: "Staging server"
      - url: "http://localhost:8080/v1"
        description: "Development server"
    
  2. 复杂版

    servers:
      - url: "https://{environment}.example.com/{version}:{port}"
        description: "Variable environment server"
        variables:
          environment:
            default: "api"
            # optional fields, enum wil restrict the selection
            # without enum, it'll be a input
            enum:
              - "api"
              - "staging-api"
              - "dev-api"
            # optional field
            # descriptions: a string value associated to the description
          port:
            enum:
              - "8443"
              - "443"
            # defaulte value is required
            default: "8443"
          version:
            default: "v1"
    

效果如下:

在这里插入图片描述

在这里插入图片描述

paths

这个是 API endpoint 在的地方了,下面这个截图是官方文档上的,现实 paths 下面具体有什么属性:

在这里插入图片描述

path object - GET

没啥好说的,直接丢实现和截图了:

paths:
  /categories:
    get:
      summary: Get all categories
      description: Returns a list of all categories
      responses:
        "200":
          description: A list of categories
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    categoryId:
                      type: integer
                    name:
                      type: string

parameters

parameters 是与 summary , response 同层级的属性, query parameter 主要是通过 in: query 确定。换句话说, path parameter 就是通过 in: path 指定

  • query parameter
    parameters:
      - name: categoryId
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 2147483647 # maximum value for a 32-bit signed integer
        description: The ID of the category to filter by
        required: false
        example: 101
    

  • path parameter
    /categories/{categoryId}:
      get:
        summary: Get a category by ID
        description: Returns a single category by its ID
        parameters:
          - name: categoryId
            in: path
            required: true
            schema:
              type: integer
              minimum: 1
              maximum: 2147483647 # maximum value for a 32-bit signed integer
            description: The ID of the category to retrieve
        responses:
          "200":
            description: A single category object
            content:
              application/json:
                schema:
                  type: object
                  properties:
                    categoryId:
                      type: integer
                    name:
                      type: string
    

path object - POST

这个结构和 GET 差的不是很多,但是 GET 没有 requestBody

从这个环节其实可以看出来,openAPI specs 会慢慢开始出现一些重复实现的对象,这点在后面会讲到需要怎么解决——主要是重复声明的 object 问题

/orders:
  post:
    summary: Create a new order
    description: Creates a new order with the provided details
    requestBody:
      required: true
      content:
        application/json:
          schema:
            type: object
            properties:
              userId:
                type: integer
                description: The ID of the user placing the order
              productIds:
                type: array
                items:
                  type: object
                  properties:
                    productId:
                      type: integer
                    quantity:
                      type: integer
                    price:
                      type: number
                      format: float
                description: List of product IDs in the order
              totalAmount:
                type: number
                format: float
                description: Total amount for the order
    responses:
      "201":
        description: Order created successfully
        content:
          application/json:
            schema:
              type: object
              properties:
                orderId:
                  type: integer

path object - PUT

POST 很相似的实现方法:

put:
  summary: Update an existing order
  description: Updates an existing order with the provided details
  requestBody:
    required: true
    content:
      application/json:
        schema:
          type: object
          properties:
            orderId:
              type: integer
              description: The ID of the order to update
            products:
              type: array
              items:
                type: object
                properties:
                  productId:
                    type: integer
                  quantity:
                    type: integer
                  price:
                    type: number
                    format: float
            address:
              type: object
              properties:
                street:
                  type: string
                city:
                  type: string
                state:
                  type: string
                zipcode:
                  type: string
            totalAmount:
              type: number
              format: float
  responses:
    "204":
      description: Order updated successfully

path object - delete

delete:
  summary: Delete an order
  description: Deletes an existing order by its ID
  parameters:
    - name: orderId
      in: query
      required: true
      schema:
        type: integer
        minimum: 1
        maximum: 2147483647 # maximum value for a 32-bit signed integer
      description: The ID of the order to delete
      example: 303
  responses:
    "204":
      description: Order deleted successfully

descriptions

这个部分总体来说还是比较简单的,这里提一下主要是因为可以使用 markdown 格式去写,实现如下:

description: |
  # About Us
  ***EazyShop*** is a leading e-commerce platform that offers a wide range of products at competitive prices. Our _API_ allows developers to integrate EazyShop's product catalog into their applications seamlessly. You will get an `Affiliate commission` for selling our products.

  # Categories supported
  - Electronics
    - Mobile Phones
    - Laptops
    - Tablets
  - Fashion
  - Home & Garden
  - Sports & Outdoors
  - Toys & Hobbies

example

这个属性在参数和返回对象中用的比较多,主要提供 example 案例让使用者可以更加直观的看到返回对象

parameters:
  - name: categoryId
    in: query
    schema:
      type: integer
      minimum: 1
      maximum: 2147483647 # maximum value for a 32-bit signed integer
    examples:
      mobiles:
        value: 101
      laptops:
        value: 102
      tablets:
        value: 103
    description: The ID of the category to filter by
    required: true
    # example: 101

examples and example cannot be used at the same time

tags

tags 提供了一个比价好的归类方法,现在所有的 endpoints 都是在 default 的分类下,看起来不是很直观:

添加了 tags 后可以更好的实现分类:

需要注意的有两点:

  1. 根目录下必须要有对应的 tags

    比如案例中,根目录里没有出现 users,那么下面的 endpoints 就无法添加 users 这个分类

  2. 一个 endpoint 可以属于多个 tags


网站公告

今日签到

点亮在社区的每一天
去签到