REST | GraphQL | gRPC | tRPC

REST api

REST(Representational State Transfer) 是一种软件架构风格,用于设计网络应用程序的 API。
REST API 就是遵循 REST 原则的 Web 接口,通常基于 HTTP 协议。

✅ 核心思想:把一切看作“资源”(Resource),通过标准 HTTP 方法对资源进行操作。

REST 的六大约束(简化版理解)

约束 含义 举例
统一接口 所有操作通过标准 HTTP 方法(GET/POST/PUT/DELETE) /books 表示“图书资源”
无状态 服务器不保存客户端状态,每次请求必须包含全部信息 用 Token 认证,而不是 Session
可缓存 响应应标明是否可缓存 GET 请求通常可缓存
分层系统 客户端无需知道是否直接连服务器(可经过代理、网关) Nginx 反向代理 FastAPI
按需代码(可选) 可返回可执行代码(如 JS) 较少用
资源标识 每个资源有唯一 URI /books/123 唯一标识 ID 为 123 的书

常用 HTTP 方法与语义

方法 含义 幂等性 安全性 例子
GET 获取资源 ✅ 是 ✅ 是 获取所有图书
POST 创建资源 ❌ 否 ❌ 否 新增一本图书
PUT 完整更新资源 ✅ 是 ❌ 否 替换 ID 为 123 的图书全部信息
PATCH 部分更新资源 ❌ 否 ❌ 否 只修改图书的标题
DELETE 删除资源 ✅ 是 ❌ 否 删除 ID 为 123 的图书

🔔 幂等性:多次执行结果相同(如 DELETE /books/123,删一次和删十次效果一样)
🔔 安全性:不改变服务器状态(GET 是安全的,POST 不是)

举个 FastAPI 的完整例子

假设你正在开发图书管理系统,下面是典型 REST API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# main.py
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List

app = FastAPI()

# 模拟数据库
books_db = [
{"id": 1, "title": "Python 入门", "author": "张三"},
{"id": 2, "title": "FastAPI 实战", "author": "李四"}
]

class BookCreate(BaseModel):
title: str
author: str

class Book(BookCreate):
id: int

@app.get("/books", response_model=List[Book])
def get_books():
return books_db

@app.post("/books", response_model=Book)
def create_book(book: BookCreate):
new_id = max(b["id"] for b in books_db) + 1 if books_db else 1
new_book = {"id": new_id, **book.dict()}
books_db.append(new_book)
return new_book

@app.get("/books/{book_id}", response_model=Book)
def get_book(book_id: int):
for book in books_db:
if book["id"] == book_id:
return book
raise HTTPException(status_code=404, detail="Book not found")

@app.put("/books/{book_id}", response_model=Book)
def update_book(book_id: int, book: BookCreate):
for b in books_db:
if b["id"] == book_id:
b.update(book.dict())
return b
raise HTTPException(status_code=404, detail="Book not found")

@app.delete("/books/{book_id}")
def delete_book(book_id: int):
for i, b in enumerate(books_db):
if b["id"] == book_id:
books_db.pop(i)
return {"message": "Deleted"}
raise HTTPException(status_code=404, detail="Book not found")

启动后,你就可以通过:

  • GET /books → 获取所有书
  • POST /books → 创建新书
  • GET /books/1 → 获取 ID=1 的书
  • PUT /books/1 → 完全替换 ID=1 的书
  • DELETE /books/1 → 删除 ID=1 的书

REST API 常见响应格式(JSON)

1
2
3
4
5
6
7
8
9
10
11
// 成功创建
{
"id": 3,
"title": "LangChain 实战",
"author": "王五"
}

// 错误
{
"detail": "Book not found"
}

HTTP 状态码也很关键:

状态码 含义
200 OK(GET 成功)
201 Created(POST 成功)
204 No Content(DELETE 成功,无返回体)
400 Bad Request(参数错误)
404 Not Found(资源不存在)
500 Internal Server Error

GraphQL

GraphQL 是由 Facebook 开发的一种 API 查询语言运行时,用于客户端精确声明它需要什么数据,服务器则按需返回这些数据。

✅ 核心理念:“客户端要什么,服务端就给什么”,避免 REST 中常见的“过载”或“多次请求”问题。

场景

你想获取用户 ID=1 的 姓名 和他最新的 两篇文章标题

🔹 REST 方式(你熟悉的方式)

1
2
GET /users/1          → 返回 {id, name, email, avatar, ...} (可能含不需要的 email/avatar)
GET /posts?userId=1 → 返回所有文章(可能有 100 篇,但你只要 2 篇)

2 次请求 + 数据冗余

🔸 GraphQL 方式

客户端发送一个 查询(Query)

1
2
3
4
5
6
7
8
query {
user(id: 1) {
name
posts(first: 2) {
title
}
}
}

服务器返回:

1
2
3
4
5
6
7
8
9
10
11
{
"data": {
"user": {
"name": "张三",
"posts": [
{"title": "Python 入门"},
{"title": "FastAPI 实战"}
]
}
}
}

1 次请求 + 精确数据

1. Schema(类型系统)

定义 API 的能力:有哪些类型?有哪些字段?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type User {
id: ID!
name: String!
posts(first: Int): [Post!]!
}

type Post {
id: ID!
title: String!
content: String
}

type Query {
user(id: ID!): User
}

2. Query(查询)

客户端请求数据(类似 REST 的 GET)

3. Mutation(变更)

客户端修改数据(类似 REST 的 POST/PUT/DELETE)

1
2
3
4
5
6
mutation {
createPost(userId: 1, title: "新文章", content: "内容") {
id
title
}
}

RPC

RPC(Remote Procedure Call) 是一种让程序调用另一个地址空间(通常是远程服务器)上的函数/过程,就像调用本地函数一样的机制。

✅ 核心思想:“像调用本地函数一样调用远程服务”

你不需要关心网络细节(HTTP、序列化等),框架会自动处理。

为什么有了 HTTP 还需要 RPC?

我们可以把 HTTP/REST 比作 “写信”,把 RPC 比作 “发电报”

A. 数据包的大小(信封 vs. 代码)

  • HTTP (REST+JSON): 为了让人看懂,JSON 极其啰嗦。
    • 比如传递一个数字 1000,JSON 需要写成字段 "balance": 1000。为了传这一个数,你得带上 "balance" 这个单词,还有大括号、冒号。这就像写信时要写满客套话。
  • RPC (Protobuf/二进制): 机器不需要看懂单词,它只需要知道位置。
    • RPC 协议会约定:“第2个位置放余额”。传输时,直接发二进制的 1000 即可。数据体积可以缩小 50%~80%。

B. 解析速度(阅读 vs. 直觉)

  • HTTP: 服务器收到 JSON 后,CPU 需要一行行去“读”文本,把字符串转换成对象。这非常消耗 CPU 资源。
  • RPC: 二进制数据到了服务器,几乎不需要转换,直接就能由计算机内存读取。解析速度比 JSON 快很多倍。

C. 约束力(口头约定 vs. 法律合同)

  • HTTP: REST API 的文档通常写在网页上(比如 Swagger)。如果后端改了字段名,前端没注意,上线可能就崩了。这属于“弱约束”。
  • RPC: 强依赖 IDL(接口定义语言)。在代码编译阶段,如果客户端和服务端定义的参数类型对不上,代码直接报错,编译不过。这大大减少了上线后的低级错误。

注意: 现代的 RPC(如 gRPC)其实底层往往也是基于 HTTP/2 协议传输的。所以准确地说,并不是“抛弃 HTTP 用 RPC”,而是“在 HTTP 之上通过 RPC 机制来优化传输效率”。

RPC 主要用于什么场景?

RPC 并不是为了取代 REST,而是为了在特定领域“称王”。

场景一:微服务架构的内部通信(这是绝对的主战场)

想象一个像淘宝或亚马逊这样的大型系统,一个“用户下单”的请求,在后台可能要触发 50 次 内部调用(查库存、算优惠、校验风控、写日志、通知物流…)。

  • 如果全用 REST:
    • 每次调用都要解析一遍 JSON,CPU 累死。
    • 每次传输都带一堆冗余的 HTTP 头,网络堵死。
    • 总延迟 = 50 次 HTTP 请求的累加,用户会感觉“卡顿”。
  • 如果用 RPC:
    • 二进制传输,极快。
    • 内部带宽占用极低。
    • 结论: 对外(给浏览器/App)用 REST,对内(服务器之间)用 RPC。

场景二:高频交易与实时系统

在股票交易、实时游戏同步等对延迟(Latency)极其敏感的场景。

  • 每一毫秒都决定盈亏。RPC 省去了繁琐的 HTTP 报文头解析,能把延迟压榨到极限。

场景三:多语言混合开发 (Polyglot)

公司里,算法团队用 Python(搞 AI),后端团队用 Java(搞业务),数据团队用 Go。

  • 使用 gRPC(Google 的 RPC 框架),只需要定义一份 .proto 文件,就能自动生成 Python、Java、Go 的代码。这三个团队不需要互相通过文档扯皮,直接调用生成的代码即

RPC 调用流程

1
2
3
4
5
6
sequenceDiagram
participant Client as 客户端
participant Server as RPC 服务端
Client->>Server: 调用 generate_summary(book_id=456)
Server->>Server: 执行本地函数(可能调用 LLM/数据库)
Server-->>Client: 返回 {summary: "...", task_id: "..."}

对比 REST 的资源操作:

1
2
3
4
5
6
sequenceDiagram
participant Client
participant REST_API
Client->>REST_API: POST /summaries {book_id: 456}
REST_API->>DB: 创建摘要任务
REST_API-->>Client: 201 Created {location: "/summaries/789"}

gRPC:跨语言的通用翻译官

gRPC 是由 Google 开发并开源的高性能 RPC 框架。它是目前微服务架构中的事实标准。

核心特点:

  1. 基于 HTTP/2: 它利用 HTTP/2 的特性(如多路复用、头部压缩),传输效率极高。
  2. Protocol Buffers (Protobuf): 这是 gRPC 的灵魂。它不使用 JSON,而是使用 Google 发明的 .proto 文件来定义接口和数据结构。
  3. 多语言支持 (Polyglot):这是它最大的杀手锏。

适用场景:

  • 微服务架构: 几十个服务,有的用 Java 写,有的用 Python 写,需要互相通信。
  • 移动端对接: 手机 App 与服务器通信(省流量、省电)。

tRPC:TypeScript 开发者的“心灵感应”

tRPC (TypeScript RPC) 是近年来在前端圈(特别是 React/Next.js 社区)爆火的库。

注意: tRPC 只能用于 TypeScript。如果你的后端是 Java 或 Go,那就不能用它。

核心特点:

  1. 端到端类型安全 (End-to-End Type Safety): 这是它存在的全部意义。
  2. 无代码生成 (No Code Gen): 不需要写 .proto 文件,也不需要运行脚本生成代码。
  3. 基于标准 HTTP: 底层通常还是普通的 HTTP 请求,但写代码的感觉是 RPC。

适用场景:

  • 全栈 TypeScript 项目: 比如使用 Next.js, Nuxt.js 等框架,前后端都在一个代码仓库(Monorepo)里。
  • 中小型快速开发: 一个团队同时负责前后端,追求极致的开发速度。

参考资料

【API技术核心原理】REST | GraphQL | gRPC | tRPC_哔哩哔哩_bilibili

RPC是什么?HTTP是什么?RPC和HTTP有什么区别?_哔哩哔哩_bilibili