Python 现代开发学习笔记

(十四)登记读取路由与参数约束

1. 让路由只连接输入和业务动作

service.py 决定怎样查记录,路由负责从 HTTP 取得输入、调用业务函数,并声明输出。把书籍入口集中放进一个 APIRouter:

# 项目文件:api_project/src/bookapi/routes/books.py
from typing import Annotated

from fastapi import APIRouter, Path, Query, Response

from .. import service
from ..dependencies import CurrentIdentity, DbSession
from ..schemas import BookCreate, BookOut, BookPage, BookPatch

router = APIRouter(prefix="/books", tags=["书籍"])
# SQLite INTEGER 使用有符号 64 位编号;过大的编号在参数校验时交回 422。
BookId = Annotated[int, Path(ge=1, le=2**63 - 1)]


@router.get("", response_model=BookPage)
def read_books(
    session: DbSession,
    identity: CurrentIdentity,
    q: Annotated[str, Query(max_length=100)] = "",
    finished: bool | None = None,
    offset: Annotated[int, Query(ge=0)] = 0,
    limit: Annotated[int, Query(ge=1, le=100)] = 20,
):
    return service.list_books(session, identity.user.id, q, finished, offset, limit)


@router.get("/{book_id}", response_model=BookOut)
def read_book(book_id: BookId, session: DbSession, identity: CurrentIdentity):
    return service.owned_book(session, book_id, identity.user.id)

APIRouter 的登记方式与 app 相似。prefix="/books" 为这组路由统一加上前缀,tags=["书籍"] 将它们归在接口页面的同一组。因此 @router.get("") 对应 GET /books,@router.get("/{book_id}") 对应单本读取。

BookId 把整数和 Path 检查组合成可复用的注解。SQLite 的整数编号保存为有符号 64 位值,这里从 1 到 2**63-1;请求超大编号时,在进入查询前得到字段错误。查询编号存在与否则由 owned_book 判断,编号 99 格式正确但没有记录,得到 404。

read_books 的三个部分可以顺着读:依赖取得会话和身份;查询参数取得筛选和分页;函数体将结果交给 service.list_books。finished 的 None 继续表示不筛选,offset=0 表示从第一条开始,limit=20 是没有提交条数时的默认值。

比较非整数编号零和超大编号停在参数校验,合法但不存在的编号进入查询得到 404,存在且归属正确的记录形成响应

笔记正文与全部题解 · Ctrl / ⌘ K