接口和接口开发的基本概念
接口和接口开发的基本概念
接口
在软件开发中,“接口”(API)通常指的是不同系统、模块、或组件之间交互的契约或协议。在前后端开发中,接口通常指的是后端服务与前端应用之间数据交换的通道。通过这些接口,前端能够请求后端的数据,后端根据前端的请求返回相应的数据或处理结果。现在每一个大模型(比如DeepSeek、GPT)都有相应的API,开发者不需要理解大模型是怎么实现的,只需要通过这些API向大模型发送请求,就可以获取模型的输出了(例如,生成文本、回答问题、翻译语言等)。比如在 OpenAI 的 GPT 系列模型中,可以通过一个 RESTful API 调用模型来生成文本,一个典型的 API 请求可能是这样的:
请求:
1
2
3
4
5
6
7
8
9POST https://api.openai.com/v1/completions
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"model": "text-davinci-003",
"prompt": "Tell me a joke about programming",
"max_tokens": 50
}在这个 JSON 请求中:
model
: 指定使用的模型,如 GPT-3 或 GPT-4。prompt
: 用户输入的提示信息。max_tokens
: 指定返回的最大字符数(通常是以 token 数量为单位)。
响应:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "cmpl-5S5bxYqT5e0MiBvYPzFp70p2yk0Wf",
"object": "text_completion",
"created": 1611894167,
"model": "text-davinci-003",
"choices": [
{
"text": "Why do programmers prefer dark mode? Because the light attracts bugs!",
"index": 0
}
]
}响应会包含模型生成的文本,在这个例子中是一个程序员笑话。那么在这里,具体哪些东西叫作“接口”?实际上这整个流程和规范都算是接口的一部分,比如:
- 通过哪个 URL 路径和服务器交互:https://api.openai.com/v1/completions
- 如何向API提交数据:POST方法
- 需要发送什么样的输入数据:包含Authorization,请求体为JSON格式,必须包含
model
、prompt
、max_tokens
等字段。 - 服务器返回的数据是什么格式:也是 JSON 格式,包含了模型的生成结果,包含
id
、model
等等字段。
实际上只要是服务器-客户端模式这类的应用,都需要进行客户端与服务端之间的交互和数据交换,也都存在接口的概念。比如 MySQL 是一个关系型数据库管理系统,通信方式遵循客户端-服务器模式。MySQL 服务器是一个持续运行的进程,负责处理数据库操作。它在后台运行,监听来自客户端的请求;客户端程序(如 MySQL Workbench、命令行工具或应用程序)向 MySQL 服务器发起请求。客户端通过发送 SQL 查询、请求数据等来与服务器进行交互。MySQL 客户端和服务器之间使用 MySQL 协议进行通信,MySQL 协议基于 TCP/IP 网络进行传输,它定义了如何将 SQL 查询、数据和响应进行编码和解码。客户端通过 TCP/IP 连接到 MySQL 服务器,发送请求并等待响应。
ANSYS也同样遵循客户端-服务器模式,在大型仿真任务中,ANSYS 服务器处理计算任务,管理并调度计算资源(如多个计算节点、集群等)。仿真计算的实际过程在服务器上运行。用户通过 ANSYS 客户端应用程序(如 ANSYS Workbench)与仿真模型进行交互,创建模型、设置边界条件、提交计算请求等。用户通过 ANSYS Workbench 启动仿真任务;客户端发送任务请求到 ANSYS 服务器,服务器开始进行计算;服务器完成计算后,结果会返回给客户端,用户查看并分析结果。在许多 ANSYS 软件版本中,客户端与服务器之间的通信使用TCP/IP 协议,并通过专门的协议进行数据交换,类似于数据库服务器的通信方式。对于分布式仿真和高性能计算(HPC)环境,ANSYS 可以通过网络将计算任务分发到多个计算节点,并通过客户端收集结果。
对于科学计算软件开发这样的场景,前后端分离是比较适合的开发模式。像ANSYS一样,前端用户界面制定请求,并将特定格式的请求发送到某个接口上,后端接收到这些请求,调度求解器进行模拟计算,并将结果返回给前端。前端开发不需对这些复杂的算法有什么过多的了解。这样,前端和后端可以独立开发、独立演进。即使前端对后端没有任何知识,项目也可以推进下去。对接口和接口开发有一些基本的概念,对于软件开发以及相关软件和应用的使用都很有帮助。上面的讨论涉及到了一些基本概念,比如 HTTP 协议、RESTful API,接口开发也涉及到一些基本的工具,这个博客是对这些基本概念的一些总结。
HTTP
HTTP 请求报文
HTTP(超文本传输协议)是互联网上应用最为广泛的一种网络协议,它可以定义客户端和服务器之间通信的规则。我们在浏览器里访问一个网页,实际上发生的事情是浏览器构造一个 HTTP GET 请求报文并发送给服务器,再将服务器返回的内容在浏览器中渲染呈现给我们。HTTP的请求报文是由请求方法、请求URI、协议版本、可选的请求首部字段和内容实体构成的。
比如下面这个例子展示了一个 HTTP POST 请求的结构,请求方法为 POST ,用于向服务器提交数据;URI 表示请求的资源路径,这里表示客户端请求的是 hackr.jp
网站上的 /form/entry
资源路径;协议版本部分表示客户端与服务器之间使用的 HTTP 协议版本为1.1;请求头部分包含了一些描述请求的原信息,告诉服务器如何处理请求;请求体部分包含了实际发送的数据。请求头部分的 Content-Type
描述了请求体数据的格式,在这里, application/x-www-form-urlencoded
表示 HTML 表单数据。 name=ueno&age=37
表示客户端提交了两个字段,name 字段的值是 ueno
,age 字段的值是 37
。在实际应用中最常使用的内容实体格式是 application/json
,比如在上面 OpenAI 的大模型接口中也使用了 JSON 作为数据传输格式。
接收到请求的服务器,会将请求内容的处理结果以响应的形式返回。开头是服务器的HTTP版本,接下来的200 OK表示请求的处理结果的状态码(status code)和原因短语(reason-phrase),下一行显示了创建响应的日期时间,是首部字段(header field)内的一个属性。接着以一空行分隔,之后的内容称为资源实体的主体。
发送 HTTP 请求
我们已经知道 HTTP 请求报文和响应的基本格式了,那么如何发送请求并返回结果呢?有很多常用的封装好的工具可以完成这一需求。curl
是一个命令行工具,假如我们要向某个 URL 发送 GET 请求,直接 curl
这个 URL 就可以了:
1 | curl https://api.example.com/data |
如果要发送 POST 请求并附带数据,可以这样做:
1 | curl -X POST https://api.example.com/submit \ |
其中 -X POST
指定请求方法为 POST,-H "Content-Type: application/json"
设置请求头,表明请求体的格式为 JSON。-d
指定请求体,这里是一个 JSON 字符串。
用各类语言库也可以发送 HTTP 请求,比如使用 Python requests
库发送一个请求:
1 | import requests |
接口开发
接口设计的不同选择
我们知道如何请求一个接口了,这时我们想设计定义自己的接口。比如对于一个材料数据库的增删查改操作,我们可能开发以下四个接口。用户向每个接口 POST 对应的请求,即可要求后台执行相应的操作。
1 | - /create/material:用于创建新材料。 |
比如我们想创建某个材料,可以设计如下的请求体和返回格式:
1 | { |
1 | { |
接口有很多种设计方式,上面是基于动作的接口设计,每个接口都表示一种操作。假如要创建其他资源,比如创建一个模型,基于这种接口设计思路可能将相应的 URL 设计为 /create/model
。 我们也可以设计一些基于资源的接口,例如:
1 | - /material/create:用于创建新材料 |
这种设计风格去除了动作动词(如 create
, delete
等),将资源放在路径前面,将操作通过路径进行指定。
我们也可以设计基于查询参数的接口,比如:
/material
:通过GET
获取所有材料,POST
创建新材料,DELETE
删除材料。- 使用查询参数来指定操作类型:
/material?action=create
:创建材料/material?action=delete
:删除材料/material?action=update
:更新材料
所以从上面的讨论可以看到,接口设计和开发可以有不同的选择。但假如整个项目没有统一的标准,比如材料数据库用基于动作的接口设计,物理数据库用基于参数的接口设计,整个项目就凌乱不清晰了。因此,我们迫切需要一些标准的接口设计规范。
###RESTful API
RESTful (Representational State Transfer,表现层状态转化,https://www.ruanyifeng.com/blog/2011/09/restful.html) API是一套流行的、标准的 API 设计规范。RESTful API 强调的是“资源”而非“操作”,并且通过标准化的 HTTP 方法(如 GET、POST、PUT、DELETE)来描述对资源的操作。在 RESTful API 中,每个接口路径都表示一种资源,每种 HTTP 方法表示对该资源的不同操作。所谓的“资源”,就是一个“实体”,比如一段文本、一张图片、或一种服务。在 RESTful 设计中,接口路径应该简洁且表达资源的含义,比如对于我们的材料数据库,
/materials
:表示“所有材料”这一资源。/materials/{id}
:表示特定 ID 的材料资源。
RESTful API 通过使用 GET、POST、PUT、DELETE 来分别对应“查询”(获取数据)、“创建”(插入数据)、“更新”(修改数据)和“删除”(删除数据)等操作。RESTful API 的设计遵循标准的 HTTP 方法和清晰的资源路径,使得 API 更加简洁、可读,并且符合资源导向的设计原则。比如对于我们的材料数据库的增删查改,基于 RESTful API 可以设计如下的接口:
查询所有材料(GET):
1 | GET /materials |
查询特定材料(GET):
1 | GET /materials/1 |
创建新材料(POST):
1 | POST /materials |
更新材料(PUT):
1 | PUT /materials/1 |
删除材料(DELETE):
1 | DELETE /materials/1 |
RESTful API 的核心就是,每个 URL 都代表一个明确的资源,例如 /materials
或 /materials/{id}
。这些资源路径表达了数据的含义,而不需要依赖于动词来描述行为。
Flask 接口开发框架
接口定义了前后端交互的标准和规则,但实际的开发和实现则需要借助开发框架来处理请求、管理数据和生成响应。Flask 是一个流行的、轻量级的 Python Web 框架,它简单易用、灵活性强、且具有高度可扩展的特点。Flask 使用 路由(routes)来将 URL 与特定的处理函数关联,允许我们根据 HTTP 请求的类型(如 GET、POST、PUT、DELETE)编写相应的逻辑。此外,Flask 不强制使用复杂的结构,开发者可以根据需求自由选择各种扩展模块,如数据库连接、身份验证等。下面是一个最简单的 Flask 案例:
1 | # app.py |
Flask(__name__)
这一行代码创建了一个 Flask 应用实例。Flask
类是 Flask 框架的核心,__name__
传递给Flask
类是当前 Python 脚本的名称。Flask 会使用这个名称来确定应用的配置、静态文件位置等。@app.route('/')
是 Flask 中的一个装饰器,用于定义 URL 路径与处理函数的映射。在这个例子中,'/'
是根路径,当用户访问http://127.0.0.1:5000/
时,Flask 会调用hello_world()
函数。app.run(debug=True)
:这行代码启动 Flask 应用,debug=True
表示启用调试模式。在调试模式下,当修改代码后,Flask 会自动重新加载应用,并显示详细的错误信息,方便开发。
Flask 非常简洁,一个“Hello, World”应用只需要非常少量的代码。此外 Flask 提供了灵活的扩展机制,开发者可以根据需要添加数据库支持、模板渲染、身份验证等功能。对于上面材料的增删查改的RESTful API,用 Flask 框架也可以很容易地开发:
1 | from flask import Flask, request, jsonify |
在这里,路由的定义更加丰富了一点。'/materials/<int:id>'
是一个包含动态部分的 URL 路径。具体来说:
/materials
:这是固定的部分,表示访问的是materials
资源。<int:id>
:这部分是动态的,<int:id>
表示路径中可以包含一个名为id
的参数,并且这个id
必须是一个整数。Flask 会在请求到来时,将 URL 中的值提取出来,并将它传递给视图函数。
例如,访问路径 /materials/3
时,Flask 会将 id
的值提取为 3
,并将其传递给视图函数。同时,通过指定 methods=['DELETE']
, Flask 这个路由只响应 DELETE 请求,也就是说,只有客户端发送 DELETE 请求到该 URL 时,才会触发该路由的视图函数。我们可以为同一个 URL 的不同请求开发不同的视图函数。
在启动了服务之后,就可以通过 curl http://127.0.0.1:5000/materials
等方式测试一下接口了。
###标准返回和异常处理
上面基本完成了整个接口的基本开发,但是还存在两个问题:1. 接口的返回没有明确的规范;2. 没有错误和异常处理。针对第一个问题,我们可以定义一个标准的返回格式,比如要求所有的接口都以两级形式返回:
code
: 错误代码,比如 0 表示成功。message
: 提示信息,描述请求的处理结果。比如:“材料信息获取成功”。result
: 包含操作结果的数据,具体的数据在result
内部嵌套。比如具体材料的JSON信息。
对于错误和异常处理,我们可以针对每一种错误编制一个错误码,方便前端明确错误类型:
1 | # 错误码定义 |
我们可以定义一个统一的 API 异常基类:
1 | # 通用 API 异常基类 |
APIException
继承了 Exception
类,表示一种自定义的异常。之后,就可以把每个视图函数包在一个 try except
里,根据不同的错误抛出 APIException
,最后统一由 except
处理。比如:
1 | # 获取单个材料信息(GET) |
接口文档
在上面,接口的基本功能已经有了,但为了前后端顺利交互,还需要制订一份详细的接口文档。实际上,正常情况下应该先制定接口文档后,再进行实际开发,保证前后端可以同时推进项目。接口文档应该描述API 的基本信息、接口的参数、返回格式等,我们可以用markdown或者word进行接口文档的编写。比如对于GET /materials/<int:id>
这个接口,可以编写如下的接口文档:
1 | # API 文档 |
就像我们前面提到的接口可以有很多种设计一样,接口文档也没有什么统一的标准和要求。为了处理由于没有标准而带来的不规范,OpenAPI 定义了一种开放的标准,用于描述和规范化 RESTful API。它使用 JSON 或 YAML 格式来描述 API 的各个方面,包括路径、请求方法、请求参数、返回类型等。OpenAPI 旨在为 API 提供标准化、自动化、可互操作的描述,使得开发者能够轻松地编写、理解、测试和维护 API。
Swagger 是一套基于 OpenAPI 标准,用于描述、生成、测试和文档化 RESTful API 的工具集。Swagger 提供了一整套工具和服务,帮助开发者更高效地定义、测试和维护 API。Swagger 工具集包括多个组件,常见的包括:
- Swagger Editor 是一个开源的基于浏览器的工具,用于编辑和生成 OpenAPI 规范文档。你可以在 Swagger Editor 中用 YAML 或 JSON 格式编写 OpenAPI 文档,并通过图形化界面实时查看生成的 API 文档。
- Swagger UI 提供了一个交互式的界面,可以展示 API 文档并允许开发者直接在浏览器中测试 API。
- Swagger Codegen 是一个工具,它可以根据 OpenAPI 定义的文档自动生成客户端代码、服务器端代码以及 API 文档。支持多种编程语言和框架...
在 Flask 中集成 Swagger 文档生成,通常使用 Flasgger 这个扩展,直接使用 pip
即可安装。Flasgger 让 Flask 应用可以使用 Swagger 注解来自动生成和展示 API 文档。下面是一个简单的示例,展示了如何为 Flask 路由生成 Swagger 文档。需要注意的是这里的 docstring 要按照 YAML 格式来编写,因此其对缩进敏感。
1 | from flask import Flask, request, jsonify |
运行脚本后,Flasgger 会根据上述注释自动生成 Swagger UI 文档,可以在浏览器中访问 http://127.0.0.1:5000/apidocs/
来查看生成的文档,并在该界面进行交互式测试。

Postman 接口测试
接口开发好之后,接下来需要进行接口测试,确保它能够按预期工作,处理请求并返回正确或合理的结果。事实上,正常情况下我们应当先准备好测试用例,再开始接口的开发工作,这样可以边测试边开发,中确保每个功能都符合设计要求,及早发现问题。Postman 是一个广泛使用的接口测试和开发工具,它能够帮助快速验证接口的功能。Postman 不仅支持基本的 HTTP 请求,还具备自动化测试的功能,能够进行接口的集成、功能和性能测试。打开 Postman 后,可以选择 New Request 来创建一个新的请求。选择 HTTP 请求类型(如 GET、POST、PUT、DELETE),输入接口的 URL 地址。可以在请求体中添加数据,设置请求头和参数。输入请求信息后,点击 Send 按钮发送请求,Postman 会返回接口的响应,包括状态码、响应时间、响应体等信息。可以查看响应的内容,并根据返回的数据判断接口是否符合预期。Postman 还允许在每个请求中编写测试脚本,以确保接口的返回结果符合预期。比如,可以检查 HTTP 状态码、响应时间、响应数据格式等。以下是一个简单的测试脚本示例:
1 | pm.test("状态码是 200", function () { |
