Skip to content

Commit 63e38d1

Browse files
committed
python strings
1 parent 481494a commit 63e38d1

File tree

11 files changed

+320
-17
lines changed

11 files changed

+320
-17
lines changed

content/posts/fastapi-response-model.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,5 +320,61 @@ async def read_item_public_data(item_id: str):
320320
return items[item_id]
321321
```
322322

323+
### Response Status Code 响应状态码
324+
就像可以指定响应模型一样, 也可以在任何路径操作中使用 `status_code` 参数声明用于响应:
325+
- `@app.get()`
326+
- `@app.post()`
327+
- `@app.put()`
328+
- `@app.delete()`
323329

330+
```Python
331+
from fastapi import FastAPI
332+
333+
app = FastAPI()
334+
335+
336+
@app.post("/items/", status_code=201)
337+
async def create_item(name: str):
338+
return {"name": name}
339+
```
340+
341+
`status_code` 是"装饰器"方法的一个参数, 而不是你的路径操作函数 *path operation function* 的参数
342+
343+
`status_code` 参数接收一个表示 HTTP 状态码的数字, 也可以接收一个 `IntEnum`, 比如 Python 中的 `http.HTTPStatus`
344+
345+
- 将在响应中返回该状态码
346+
- 并在 OpenAPI 模式中也如此记录
347+
348+
#### About HTTP status codes
349+
在 HTTP 协议中, 会在响应中发送一个3位数的数字状态码
350+
351+
这些状态码又一个相关联的名称便于识别, 但重要的是数字本身
352+
353+
- 100~199: 用于"信息", 很少会直接使用它们, 这些状态码的响应不能有响应体
354+
- 200~299: 用于"成功"的响应, 这些是最常用的
355+
- 200 的默认的"成功"响应, 表示一切 OK
356+
- 201 表示已创建, 通常在数据库中创建新记录后使用
357+
- 204 表示无内容, 当没有内容返回给客户端时使用此响应, 因此不能有响应体
358+
- 300~399: 用于"重定向", 这些状态码的响应可能有也可能没有响应体. 但 304 (未修改) 除外, 它必须没有响应体
359+
- 400~499: 用于"客户端错误"响应,
360+
- 404 用于"未找到"的响应
361+
- 400 客户端通用错误
362+
- 500~599: 用于服务器错误, 几乎从不直接使用它们. 当的应用代码或服务器的某个部分出错时, 它会自动返回这些状态码之一
363+
364+
要了解更多关于每个状态码的信息以及哪个代码用于什么目的,请查阅 [MDN 关于 HTTP 状态码的文档](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status)
365+
366+
#### Shortcut to remember the names
367+
除了直接使用数字外, 还可以使用 `fastapi.status` 中的便捷变量
368+
```Python
369+
from fastapi import FastAPI, status
370+
371+
app = FastAPI()
372+
373+
@app.post("/items/", status_code=status.HTTP_201_CREATED)
374+
async def create_item(name: str):
375+
return {"name": name}
376+
```
377+
这只是一直便利, 都是一样的树枝, 但这样可以使用编辑器的自动补全功能
378+
379+
> 也可以使用 `from starlette import status`
324380

content/posts/microservice-apis.md

Lines changed: 130 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
+++
22
date = '2025-08-02T10:00:00+08:00'
33
draft = true
4-
title = 'Microservice APIs'
4+
title = 'Microservice with FastAPI'
55
+++
66

7-
### What are microservices ?
8-
什么是 microservices? 微服务可以有多种不同的定义方式, 具体取决于希望强调微服务架构的哪个方面, 不同作者会给出略有不同但相关的定义
7+
## What are microservices ?
8+
什么是微服务? 微服务可以有多种不同的定义方式, 具体取决于希望强调微服务架构的哪个方面, 不同作者会给出略有不同但相关的定义
99

1010
Sam 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):
117117
def 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

content/posts/python-strings.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
+++
2+
date = '2025-08-13T10:00:00+08:00'
3+
draft = false
4+
title = 'Python Strings'
5+
+++
6+
7+
这篇文章总结一下 Python 中字符串的类型
8+
9+
### Unicode String 字符串
10+
u 在 Python3 中是多余的, 因为所有的普通字符串默认都是 Unicode, 但在 Python2 中, u 用来显示的表示 Unicode 字符串, 现在保留这个是为了向后兼容
11+
12+
13+
### Fromatted String 格式化字符串
14+
f 前缀用于创建格式化字符串, 这是最常见的字符串格式方法, 运行在字符串中嵌入表达式, 在求值时转换为普通的 `str`
15+
```Python
16+
name = "World"
17+
greeting = f"Hello, {name}!" # 结果: "Hello, World!"
18+
```
19+
20+
### Raw String 原始字符串
21+
r 前缀用于创建原始字符串, 会忽略反斜杠 `\` 的转义功能, 在编写文件路径或正则表达式的时候非常有用, 可以避免大量的反斜杠转义
22+
```Python
23+
path = r"C:\Users\Documents" # 单个反斜杠 '
24+
regex = r"\bword\b" # \b 不会被转义
25+
```
26+
27+
### Bytes String 字节串
28+
b 前缀用于创建字节串字面量, 表示一个不可变的字节序列, 而不是 Unicode 文本, 字节串主要用于二进制数据, 例如图像文件、网络数据或压缩文件等
29+
```Python
30+
binary_data = b"Hello" # 存储的是 ASCII 编码的字节
31+
```
32+
33+
### Template String 模板字符串
34+
t 前缀用于创建模板字符串, 这是 Python 3.14 引入的新功能, 由 [PEP 750](https://peps.python.org/pep-0750/) 通过.
35+
36+
不同于 f-string, t-string 不会立即求值为 `str`, 而是求值为一个 Template 对象, 这为开发者提供了将在将字符串和插值组合之前进行处理(和安全转义)的能力
37+
38+
```Python
39+
from string.templatelib import Template
40+
template = t"Hello, {name}" # template 是一个 Template 对象
41+
```
42+
43+
44+
### 组合使用
45+
| 前缀 | 含义 | 用途 |
46+
| :--- | :----- | :--- |
47+
| f | 格式化 | 嵌入变量和表达式 |
48+
| r | 原始 | 忽略反斜杠转义 |
49+
| b | 字节 | 处理二进制数据 |
50+
| t | 模板 | 在组合前处理插值 |
51+
| u | Unicode | Python 3 中默认开启 |
52+
| fr / rf | 格式化+原始 | 在正则表达式中嵌入变量 |
53+
| br / rb | 字节+原始 | 忽略二进制数据中的转义 |
54+
| tr / rb | 模板+原始 | 模板中处理原始文本 |

public/archives/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
posts</p></div></div><div class="relative mb-8"><div class="relative mb-4 flex items-center"><div class="bg-accent border-background absolute left-2 z-10 h-4 w-4 rounded-full border-2"></div><div class=ml-12><h3 class="text-foreground text-lg font-semibold">August 2025</h3><p class="text-muted-foreground text-xs">11
5757
posts</p></div></div><div class="ml-12 space-y-3"><article class="group bg-card border-border hover:bg-accent/50 rounded-lg border p-4 transition-all duration-300"><div class="flex items-center justify-between gap-4"><div class="min-w-0 flex-1"><h4 class="text-foreground group-hover:text-primary mb-3 font-medium transition-colors duration-200"><a href=/posts/fastapi-response-model/ class=block>FastAPI Response Model</a></h4><div class="text-muted-foreground flex items-center gap-4 text-xs"><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
5858
<time datetime=2025-08-12>08-12</time></div><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3A9 9 0 113 12a9 9 0 0118 0z"/></svg>
59-
<span>5
59+
<span>6
6060
min</span></div></div></div></div></article><article class="group bg-card border-border hover:bg-accent/50 rounded-lg border p-4 transition-all duration-300"><div class="flex items-center justify-between gap-4"><div class="min-w-0 flex-1"><h4 class="text-foreground group-hover:text-primary mb-3 font-medium transition-colors duration-200"><a href=/posts/fastapi-cookie-and-header-parameters/ class=block>Fastapi Cookie and Header Parameters</a></h4><div class="text-muted-foreground flex items-center gap-4 text-xs"><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
6161
<time datetime=2025-08-11>08-11</time></div><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3A9 9 0 113 12a9 9 0 0118 0z"/></svg>
6262
<span>3

public/en/sitemap.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?xml version="1.0" encoding="utf-8" standalone="yes"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"><url><loc>https://starslayerx.github.io/posts/fastapi-response-model/</loc><lastmod>2025-08-12T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/</loc><lastmod>2025-08-12T10:00:00+08:00</lastmod><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/posts/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/posts/"/></url><url><loc>https://starslayerx.github.io/posts/fastapi-cookie-and-header-parameters/</loc><lastmod>2025-08-11T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/python-function-parameters/</loc><lastmod>2025-08-10T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/fastapi-body-advanced-uses/</loc><lastmod>2025-08-09T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/git-whitelist/</loc><lastmod>2025-08-08T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/fastapi-parameters-and-validations/</loc><lastmod>2025-08-07T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/fastapi-parameters/</loc><lastmod>2025-08-06T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/python-tricks/</loc><lastmod>2025-08-05T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/executing-arbitrary-python-code-from-a-comment/</loc><lastmod>2025-08-04T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/how-fastapi-works/</loc><lastmod>2025-08-01T10:30:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/blaugust/</loc><lastmod>2025-08-01T10:00:00+08:00</lastmod><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/posts/blaugust/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/posts/blaugust/"/></url><url><loc>https://starslayerx.github.io/</loc><lastmod>2023-01-01T08:00:00-07:00</lastmod><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/"/></url><url><loc>https://starslayerx.github.io/archives/</loc><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/archives/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/archives/"/></url><url><loc>https://starslayerx.github.io/categories/</loc><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/categories/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/categories/"/></url><url><loc>https://starslayerx.github.io/tags/</loc><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/tags/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/tags/"/></url></urlset>
1+
<?xml version="1.0" encoding="utf-8" standalone="yes"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"><url><loc>https://starslayerx.github.io/posts/</loc><lastmod>2025-08-13T10:00:00+08:00</lastmod><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/posts/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/posts/"/></url><url><loc>https://starslayerx.github.io/posts/fastapi-response-model/</loc><lastmod>2025-08-12T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/fastapi-cookie-and-header-parameters/</loc><lastmod>2025-08-11T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/python-function-parameters/</loc><lastmod>2025-08-10T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/fastapi-body-advanced-uses/</loc><lastmod>2025-08-09T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/git-whitelist/</loc><lastmod>2025-08-08T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/fastapi-parameters-and-validations/</loc><lastmod>2025-08-07T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/fastapi-parameters/</loc><lastmod>2025-08-06T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/python-tricks/</loc><lastmod>2025-08-05T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/executing-arbitrary-python-code-from-a-comment/</loc><lastmod>2025-08-04T10:00:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/how-fastapi-works/</loc><lastmod>2025-08-01T10:30:00+08:00</lastmod></url><url><loc>https://starslayerx.github.io/posts/blaugust/</loc><lastmod>2025-08-01T10:00:00+08:00</lastmod><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/posts/blaugust/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/posts/blaugust/"/></url><url><loc>https://starslayerx.github.io/</loc><lastmod>2023-01-01T08:00:00-07:00</lastmod><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/"/></url><url><loc>https://starslayerx.github.io/archives/</loc><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/archives/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/archives/"/></url><url><loc>https://starslayerx.github.io/categories/</loc><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/categories/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/categories/"/></url><url><loc>https://starslayerx.github.io/tags/</loc><xhtml:link rel="alternate" hreflang="zh-CN" href="https://starslayerx.github.io/zh-cn/tags/"/><xhtml:link rel="alternate" hreflang="en-US" href="https://starslayerx.github.io/tags/"/></url></urlset>

0 commit comments

Comments
 (0)