3. OpenAPI 规范入门:历史、核心概念与 YAML/JSON 基础
聊到 API 规范化开发,OpenAPI 是绕不开的基石。我个人习惯把它看作 API 世界的“普通话”——不管前端后端、微服务还是单体,大家用同一套语法描述接口,沟通成本瞬间降下来。
这一章,我们从头捋一捋 OpenAPI 的来龙去脉,再上手它的核心概念和描述语言。嗯,都是干货,但我会尽量讲得轻松点。
3.1 OpenAPI 的前世今生
OpenAPI 最初不叫 OpenAPI。它最早是 Swagger 规范,由 SmartBear 公司在 2011 年推出。那时候 RESTful API 刚火起来,大家各自写文档,格式五花八门。Swagger 的出现,相当于给 API 文档定了个“标准模板”。
2015 年,Swagger 规范被捐赠给 OpenAPI Initiative(OAI),改名为 OpenAPI Specification(OAS)。从 2.0 到 3.0,再到现在的 3.1,版本迭代背后是社区对 API 描述能力的持续打磨。
几个关键时间点:
| 版本 | 发布时间 | 主要变化 |
|---|---|---|
| Swagger 2.0 | 2014 | 奠定基础,广泛采用 |
| OpenAPI 3.0 | 2017 | 重构结构,支持回调、链接、多服务器 |
| OpenAPI 3.1 | 2021 | 对齐 JSON Schema 2020-12,增强可扩展性 |
3.2 OpenAPI 的核心概念
OpenAPI 文档本质上是一个 JSON 或 YAML 文件,它描述了一个 API 的全部信息。说白了,就是告诉别人:你的 API 长什么样,能干什么,怎么调用。
核心结构拆解:
- openapi:版本声明,比如
3.1.0。 - info:API 的元信息,标题、版本、描述。
- servers:API 的访问地址,可以配多个(开发、测试、生产)。
- paths:API 的路径和操作,这是最核心的部分。
- components:可复用的数据模型、参数、响应等。
- tags:分组标签,方便文档归类。
你想想看,一个 API 文档如果连这些基本信息都没有,别人怎么用?
核心原则: OpenAPI 文档应该是“自描述”的。拿到它,不需要额外沟通,就能直接生成客户端 SDK、服务端桩代码、测试用例。
3.3 YAML 与 JSON:两种描述语言
OpenAPI 支持 YAML 和 JSON 两种格式。我个人更偏爱 YAML,因为它可读性更好,缩进结构一目了然。但 JSON 在机器解析和工具链支持上更成熟。
一个简单的对比:
| 特性 | YAML | JSON |
|---|---|---|
| 可读性 | 高,缩进清晰 | 中,括号多 |
| 注释支持 | 支持 # 注释 | 不支持 |
| 工具链 | 较新,但已成熟 | 非常成熟 |
| 文件大小 | 通常更小 | 稍大 |
3.4 第一个 OpenAPI 文档:从零开始
我们直接上手写一个。假设有一个用户查询接口,GET /users/{id},返回用户信息。
YAML 版本:
openapi: 3.1.0
info:
title: 用户服务 API
version: 1.0.0
description: 提供用户信息的查询接口
servers:
- url: https://api.example.com/v1
paths:
/users/{userId}:
get:
summary: 根据 ID 获取用户
parameters:
- name: userId
in: path
required: true
schema:
type: integer
responses:
'200':
description: 成功返回用户信息
content:
application/json:
schema:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
id:
type: integer
name:
type: string
email:
type: string
JSON 版本(等价):
{
"openapi": "3.1.0",
"info": {
"title": "用户服务 API",
"version": "1.0.0",
"description": "提供用户信息的查询接口"
},
"servers": [
{ "url": "https://api.example.com/v1" }
],
"paths": {
"/users/{userId}": {
"get": {
"summary": "根据 ID 获取用户",
"parameters": [
{
"name": "userId",
"in": "path",
"required": true,
"schema": { "type": "integer" }
}
],
"responses": {
"200": {
"description": "成功返回用户信息",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/User" }
}
}
}
}
}
}
},
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"email": { "type": "string" }
}
}
}
}
}
看到没?YAML 少了花括号和逗号,结构更清爽。但 JSON 在自动化工具中更稳定。
3.5 核心概念深度解析
我们挑几个容易踩坑的点细说一下。
3.5.1 Paths 与 Operations
paths 下面每个路径可以挂多个操作(get、post、put、delete 等)。每个操作里,parameters、requestBody、responses 是三大块。
参数类型:
- path:路径参数,比如 /users/{id} 里的 id。
- query:查询参数,比如 ?page=1。
- header:请求头参数。
- cookie:Cookie 参数。
3.5.2 Components 与 $ref
components 是用来定义可复用组件的。最常见的是 schemas(数据模型),还有 parameters、responses、requestBodies 等。
$ref 是引用机制,类似编程中的 import。比如 $ref: '#/components/schemas/User' 就是引用上面定义的 User 模型。
为什么用 $ref? 避免重复定义。一个 User 模型可能在多个接口中出现,写一次,到处引用。维护起来也方便——改一处,全更新。
3.5.3 数据模型与 JSON Schema
OpenAPI 3.1 的数据模型直接基于 JSON Schema 2020-12。这意味着你可以用 type、properties、required、enum、oneOf、anyOf 等关键字来描述复杂结构。
举个例子:
components:
schemas:
Order:
type: object
required:
- id
- total
properties:
id:
type: integer
total:
type: number
format: float
items:
type: array
items:
$ref: '#/components/schemas/OrderItem'
OrderItem:
type: object
properties:
productId:
type: integer
quantity:
type: integer
这里 Order 引用了 OrderItem,形成了一个嵌套结构。JSON Schema 的威力就在这里——你可以描述任意复杂的数据契约。
3.6 知识体系总览
为了让你更直观地理解 OpenAPI 的整体结构,我画了一张图。
这张图把 OpenAPI 文档的骨架画出来了。你写文档时,就按这个结构填充内容。路径和组件是两大核心,其他都是辅助信息。
3.7 工具链与生态
OpenAPI 的生态非常丰富。我常用的几个工具:
- Swagger Editor:在线编辑器,实时预览文档。
- Swagger UI:根据文档生成交互式 API 文档页面。
- OpenAPI Generator:根据文档生成客户端 SDK 和服务端桩代码。
- Redoc:另一个文档渲染工具,风格更简洁。
这些工具都遵循 OpenAPI 规范。你只要写好文档,剩下的交给工具链。
3.8 避坑指南
最后分享几个我踩过的坑:
- 缩进问题:YAML 缩进必须一致,建议用 2 个空格。别混用 Tab 和空格。
- $ref 路径:引用 components 时,路径要写对。比如
#/components/schemas/User,少个斜杠都不行。 - 版本声明:openapi 字段必须写对版本号,比如 3.1.0。写错会导致解析失败。
- 响应定义:每个操作至少定义一个 200 响应,否则工具链会警告。