Web 开发: API 设计
需要关注的主题:
- RESTful API
- Open API 标准: 用于编写 API 文档
- Swagger: 用于可视化文档
- HTTP Verb
- CORS
- HTTP Server
- Route
- 内置的 mux
- httproute
- gorilla/mux
- 避免 SQL injection 的问题需要时刻关注, 因为在 path 或 body 中的任何字符串都可能被用于攻击.
1 Web 开发基础: API Design
本节对应 TS 书的 C1 ~ C3.
为能发挥一门技术的最大潜力, 必须深入了解这个技术.
RESTful API 开发需要了解的有:
- REST 定义
- RESTful 风格
- REST 中的常见概念
- HTTP methods 和 verbs
什么是 REST?
RESTful API 是使用 REST 原则开发的 web 服务. 那什么是 REST 呢?
REST 又称为 REST 风格, 是一系列软件工程实践(或一系列约束), 用于创建 web 服务.
REST 是一种架构风格而非工具集, 它提供设计规则来创建通过资源(Resource)表示的无状态(Stateless)服务. 使用 URI 唯一标识资源.
客户端通过 URI 并指定 HTTP method 来访问资源, 资源以某种约定的形式返回, 而返回的资源表现形式一般都是文档, 这些文档反映了资源当前(或预期)的状态表现.
REST 架构风格
REST 架构风格包含 6 个约束:
- Uniform Interface
- Stateless
- Cacheable
- Client/Server architecture
- A layered system
- Code on Demand
Uniform Interface
统一接口用于描述客户端和服务器间的通信约定. 统一接口约束中又包含如下四个设计原则:
- 基于资源的接口
- 通过资源的表现来操作资源
- 自描述的信息
- HATEOAS(超媒体作为应用状态的引擎)
下面详细看看这四个原则.
基于资源的接口
资源通过 URI 标志, URI 用于唯一标识资源. 客户端通过 URI 请求服务器, 服务器返回对应资源的对应表现形式.
通过资源的表现来操作资源
客户端请求资源后, 服务器返回的是资源当前状态的对应表现形式(即资源表现形式可以被客户端指定, 比如 JSON, XML 等).
自描述的信息
服务器返回的数据中可能包含除资源当前状态的表现形式外的额外信息, 并且额外信息可以通过 link 表示. 此外, 客户端请求资源时可以在 Header 中使用 MIME type 指定需要的资源类型. (TS 书的 P12 有 MIME type 的表格)
HATEOAS(超媒体作为应用状态的引擎)
通过在响应中携带导航 link, 客户端可以通过 link 在前一个响应的基础上获取更多补足信息. Github API 就有这些内容(比如响应中的的 links 数组)
Stateless
无状态指的是: 客户端状态不会在服务器侧体现, 服务端不会维护某个客户的"上一次请求状态", 每次客户端的请求总是携带完整的信息. 服务端处理请求后, 资源的状态可能变化, 资源的当前状态表现形式会被响应带回到客户端.
无状态可以让服务端的扩容变得非常容易, 因为服务端不需要维护 Session, 而且负载均衡也不用关注 Session.
Cacheable
使用缓存的目的是避免重复生成相同的响应. 在实践时, 请求会先经过一个或一系列的 Cache(比如本地缓存, 代理缓存, 反向代理缓存等).
逻辑上可以将这些缓存服务器理解为一个缓存层, 如果没有找到对应缓存, 才会将请求发送到实际资源服务器.
客户端/服务器结构
使用 C/S 结构以确保客户端或服务器都可 以单独改变, 二者间通过接口沟通, 这样它们间可以没有任何耦合. 客户端不会关心服务器的数据库用什么, 服务器也不用担心客户端的界面如何实现.
A Layered System
分层的目的是对职责进行划分, 每层都独立工作且只与它直连的层进行通信, 且这样可以让请求在每层间按顺序流转.
Code on demand
这条是可选的模式, 允许客户端从服务器下载代码并在本地运行.
HTTP methods
有如下 HTTP 方法可用:
- GET: 从服务器获取特定的资源, 而绝不会修改任何资源, 如果资源状态没有变化, 则任何时候通过 GET 获取到的资源表示都是一致的.
- HEAD: 和 GET 类似, 只不过它仅获取响应头
- POST: 通常用于创建资源
- PATCH: 用于修改资源, 仅修改部分细节(比如更新日期, 修改名称等)
- PUT: 用于修改资源, 不过是用于修改整个资源
- DELETE: 删除资源
- CONNECT: 将连接请求转换为透明的 TCP/IP 隧道, 通常用于在未加密的 HTTP 代理上创建 SSL 加密通信
- OPTIONS: 用于请求对应 URL 支持的所有 HTTP 方法
- TRACE: 用于检查是否中间服务器会对请求进行修改(如果没有修改, 响应内容应和请求一致)
2 RESTful API 创建原则
关注点:
- 如何组织 API 端点: URL 的给出方式
- API 的暴露方式: 区分公共和私有
- 如何处理大规模数据集: 使用分页(offset and limit), 排序, 搜索
- 命名约定: 根据资源情况进行
- API 版本: 如果不是公共 API 可以暂时不用考虑, 有三种方式放版本号: 1)放到 path 中 2)放到 Header 中 3)放到 subdomain 中
- HTTP 状态码
HTTP 状态码
简单列出一些常见的, 需要时查网上即可.
- 1xx: 用于提供信息
- 2xx: 成功
200 OK
: 表示成功201 Created
: 通常用于资源创建型的请求响应(比如 POST), 响应体应携带创建后的资源 URL202 Accepted
: 通常用于异步处理过程的响应204 No Content
: 表示没有响应体, 通常用于 DELETE 请求的响应
- 3xx: 重定向
301 Moved Permanently
: 永久移动304 Not Modified
: 通常用于缓存层直接返回的情况
- 4xx: 客户端错误
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
405 Method Not Allowed
406 Not Acceptable
409 Conflict
415 Unsupported Media Type
429 Too Many Request
- 5xx: 服务端错误
500 Internal Server Error
503 Service Unavailable
使用 Swagger 设计 RESTful API (OpenAPI 规范)
在开发实践时, 可以使用 API First 的方式进行. 即通过 Open API 设计 API 并使用 Swagger UI 作为团队沟通工具提前发布 API 规则, 然后前端和后端可以同步进行开发.
Swagger 工具可以进行:
- API 建模(Swagger Editor, 使用 OpenAPI 描述)
- 生成可读的 API 文档(Swagger UI)
- 生成客户端/服务端代码(Swagger Codegen)
OAS(OpenAPI Specification) 描述是大小写敏感的. OAS 有自己的数据类型定义. 具体可以看它的官方: https://editor.swagger.io/.
目前理解的工作流:
- API First 设计 -> 前后端开发 -> 后端开发完成后统一再生成一次 Swagger 文档, 这样循环往复
- API First 设计 -> 后端生成代码 -> 前后端开发 -> API First 设计完善 -> 后端生成代码 -> 确认无误继续开发 循环往复
用 Swagger 时 yaml 比 json 的行数更少, 推荐 yaml.
实例: URL shorter
需求:
- 用户可以请求一个完整 URL 的短 URL 形式
- 用户访问现在 host 的短 URL 的时候, 自动重定向到指定的 URL
实现细节:
- 将 URL 转换为对应的 BASE62 编码字符串
- 将对应关系存放到数据库
- 用户请求时, 判断 URL, 在服务端发送重定向, 浏览器即可重定向到指定 URL.