11+++
22date = ' 2025-08-02T10:00:00+08:00'
33draft = true
4- title = ' Microservice APIs '
4+ title = ' Microservice with FastAPI '
55+++
66
7- ### What are microservices ?
8- 什么是 microservices ? 微服务可以有多种不同的定义方式, 具体取决于希望强调微服务架构的哪个方面, 不同作者会给出略有不同但相关的定义
7+ ## What are microservices ?
8+ 什么是微服务 ? 微服务可以有多种不同的定义方式, 具体取决于希望强调微服务架构的哪个方面, 不同作者会给出略有不同但相关的定义
99
1010Sam Newman, 微服务领域最有影响力的作者之一, 给出了一个极简的定义:
1111
@@ -28,7 +28,7 @@ James Lewis 和 Martin Fowler 撰写的一篇开创性文章提供了一个更
2828
2929
3030
31- ### A basic API implementation
31+ ## A basic API implementation
3232这里通过一个 CoffeeMesh 项目的 orders service (订单服务) api 介绍微服务
3333
3434首先给出 OpenAPI 格式的 API 定义文档 [ oas.yaml] ( https://github.com/abunuwas/microservice-apis/blob/master/ch02/oas.yaml ) , 可以通过 [ Swagger UI] ( https://editor.swagger.io/ ) 来查看该文档内容 (OAS 代表 OpenAPI specification/规范, 是一种标准的 REST API 文档)
@@ -117,4 +117,130 @@ def cancel_order(order_id: UUID):
117117def pay_order(order_id : UUID):
118118 return order
119119` ` `
120+ 现在有了 API 的基本骨架, 后面将继续实现 incoming payload 和 outgoing response 的验证
121+
122+
123+ ### Implementing data validation models with pydantic
124+ 这里介绍 data validation 和 marshalling
125+
126+ > "Marshalling" 指的是将一个内存中的数据结构转换成一种适合存储或通过网络传输的格式.
127+ > 在 Web API 的上下文中, Marshalling 特指将一个对象转换为一个数据结构(比如 JSON 或 XML).
128+ > 以便将其序列化为所选的内容类型, 同时明确指定对象属性的映射关系
129+
130+ 点单系统包含了3个shcemas: ` CreateOrderSchema`, `GetOrderSchema` 和 `OrderItemSchema`, 可以在[oas.yaml](https://github.com/abunuwas/microservice-apis/blob/master/ch02/oas.yaml#L211)查看
131+
132+ 下面使用 Pydantic 实现对应 schema, 可以在 [schema.py](https://github.com/abunuwas/microservice-apis/blob/master/ch02/orders/api/schemas.py)找到
133+
134+ ` ` ` Python
135+ from enum import Enum
136+
137+ class Size(Enum):
138+ small = "small"
139+ medium = "medium"
140+ big = "big"
141+
142+ class StatusEnum(Enum):
143+ created = "created"
144+ paid = "paid"
145+ progress = "progress"
146+ cancelled = "cancelled"
147+ dispatched = "dispatched"
148+ delivered = "delivered"
149+ ` ` `
150+ 对于只能从特定值中选择的类型, 定义枚举类型 `Size` 和 `StatusEnum`
151+
152+
153+ ` ` ` Python
154+ class OrderItemSchema(BaseModel):
155+ product: str
156+ size: Size
157+ quantity: conint(ge=1, strict=True) | None = 1
158+ ` ` `
159+ 将 `OrderItemSchema` 的属性设置为 `conint`, 这将强制使用整数值, 并且规定数值要大于等于1, 以及默认值1
160+
161+
162+ ` ` ` Python
163+ class CreateOrderSchema(BaseModel):
164+ order: conlist(OrderItemSchema, min_items=1)
165+
166+ class GetOrderSchema(CreateOrderSchema):
167+ id: UUID
168+ created: datetime
169+ status: StatusEnum
170+
171+ class GetOrdersSchema(BaseModel):
172+ orders: List[GetOrderSchema]
173+ ` ` `
174+ 使用 pydantic 的 `conlist` 类型定义了 `CreateOrderSchema` 的 `order` 属性, 要求列表至少有一个元素
175+
176+ # ## Validating request payloads with pydantic
177+ 上面实现了模型定义, 现在通过将其声明为视图函数的一个参数来拦截请求负载, 并通过将其类型设置为相关的 Pydantic 模型进行验证
178+
179+ 代码可以在[api.py](https://github.com/abunuwas/microservice-apis/blob/master/ch02/orders/api/api.py)里找到
180+ ` ` ` Python
181+ from uuid import UUID
182+
183+ from starlette.response import Response
184+ from starlette import status
185+
186+ from orders.app import app
187+ from orders.api.schemas import CreateOrderSchema # 导入数据模型
188+
189+ @app.post("/orders", status_code=status.HTTP_201_CREATED)
190+ def create_order(order_details: CreateOrderSchema):
191+ return order
192+
193+ @app.get("/orders/{order_id}")
194+ def get_order(order_id: UUID):
195+ return order
196+
197+ @app.put("/orders/{order_id}")
198+ def update_order(order_id: UUID, order_details: CreateOrderSchema):
199+ return order
200+ ` ` `
201+
202+ 如果发送一个有问题的数据(例如移除 product 字段), FastAPI 将会生成一份错误消息.
203+ ` ` ` JSON
204+ {
205+ "detail": [
206+ {
207+ "loc": [
208+ "body",
209+ "order",
210+ 0,
211+ "product"
212+ ],
213+ "msg": "field required",
214+ "type": "value_error.missing"
215+ }
216+ ]
217+ }
218+ ` ` `
219+ 该错误消息使用 JSON Pointer 来指示问题所在, JSON Pointer 是一种语法, 用来表示 JSON 文档中特定值的路径
220+
221+ 例如, `loc : /body/order/0/product` 大概等同于 Pytohn 中的以下表示法 `loc['body']['order'][0]['product']`
222+ - body 指的是请求的主体部分
223+ - order 指的是主体中的 order 键
224+ - 0 指的是 order 列表中的第一个元素
225+ - product 指的是这个元素中的 product 键
226+
227+ 有时候参数可能是可选的, 但是并不能为 null. 这里使用 Pydantic 的 `validator()` 装饰器来添加额外的规则
228+
229+ ` ` ` Python
230+ from pydantic import BaseModel, conint, validator
231+
232+ ...
233+
234+ class OrderItemSchema(BaseModel):
235+ product: int
236+ size: Size
237+ quantity: conint(ge=1, strict=True) | None = 1
238+
239+ @validator('quantity')
240+ def quantity_non_nullable():
241+ assert value is not None, "quantity may not be None"
242+ return value
243+ ` ` `
244+
245+ # ## Marshalling and validating response payloads with pydantic
120246
0 commit comments