FastAPI 的初体验
如果你习惯 Spring Boot 里的 @SpringBootApplication、@RestController、@RequestBody 和统一的 Result<T>,第一次看 FastAPI 时,可以把 应用入口 想成 SpringApplication.run,把 路由 想成带 @RequestMapping 的 Controller,把 Pydantic 模型 想成 DTO / 校验 Bean。下面结合学习用的 fastapi-demo 项目,串一条最小但完整的路径。
应用入口:相当于「主类 + 扫包注册 Controller」
main.py 里创建 FastAPI() 实例,再把各模块的 APIRouter 挂上去,并挂载静态资源。对应 Spring 里通常是:一个主类 + @ComponentScan 自动发现 Controller;这里则是 显式 include_router,更像手动把各个 @Configuration 或 RouterFunction 注册进主应用。
# 1:13:main.py
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from controller.IndexController import router as index_router
from controller.AboutController import router as about_router
from controller.AuthController import router as auth_router
app = FastAPI()
app.include_router(index_router)
app.include_router(about_router)
app.include_router(auth_router)
app.mount("/static", StaticFiles(directory="static"), name="static")
app = FastAPI():应用本体,类似内嵌 Tomcat 的那个应用上下文。include_router:把别的文件里定义的router合并进主应用,路径前缀可在include_router(..., prefix="/api")里统一加(当前未加前缀,所以各路由文件里写的路径就是最终路径)。mount("/static", ...):类似 Spring MVC 里对classpath:/static/的静态资源映射,这里指向本地static目录。
统一返回体:像 Result<T> / CommonResult
Java 里常封装 code、message、data。这里用 entity/R.py 里的 R 和 success / error 辅助函数表达同一意图(注意:文件名叫 R.py,from entity import R 时这里的 R 实际是 模块,R.success 即模块级函数,不是 Java 那种静态方法写在类里,但用法上很像「Result.ok()」)。
# 1:13:entity/R.py
def success(message: str, data: object = None):
return R(200, message, data)
def error(code: int, message: str, data: object = None):
return R(code, message, data)
class R:
def __init__(self, code: int, message: str, data: object = None):
self.code = code
self.message = message
self.data = data
进阶提示:若要让 OpenAPI 文档里响应结构完全固定,往往会再包一层 Pydantic 的响应模型;当前直接返回自定义对象,能跑通,和 Spring 里直接返回 POJO 类似,细节可以后面再 refine。
最简接口:@GetMapping("/") 的对应物
IndexController 里用 APIRouter(),在函数上用 @router.get("/"),等价于在类上 @RequestMapping 再 @GetMapping 到根路径。
# 1:9:controller/IndexController.py
from fastapi import APIRouter
from entity import R
router = APIRouter()
@router.get("/")
def index():
return R.success("success")
Python 里没有「类上贴注解」的强制习惯,很多教程会把一簇路由放在一个模块里,导出同一个 router,这和 Spring 6 里 RouterFunction 或「一个 @RestController 类」都是同一种组织方式,只是风格不同。
登录 + DTO + JWT:像 LoginRequest + JwtUtil
LoginRequest:对应带校验的 DTO,用 Pydantic 的BaseModel,字段可以写Field(..., title="用户名"),会出现在自动生成的 Swagger 里,有点像 Bean Validation + OpenAPI 注解的合体。@router.post("/login"):等价@PostMapping("/login")。- 函数参数
request: LoginRequest:FastAPI 会按 Content-Type: application/json 把 body 反序列化并校验,类似@RequestBody LoginRequest request。
# 1:28:controller/AuthController.py
import datetime
import jwt
from fastapi import APIRouter
from entity import R
from pydantic import BaseModel, Field
router = APIRouter(tags=["Auth"])
class LoginRequest(BaseModel):
username: str = Field("", title="用户名")
password: str = Field("", title="密码")
@router.post("/login")
def login(request: LoginRequest):
if request.username == "admin" and request.password == "admin":
# JWT
token = jwt.encode(
{
"username": request.username,
"exp": datetime.datetime.now() + datetime.timedelta(days=1)
},
"secret",
algorithm="HS256"
)
return R.success("登陆成功", {"token": token})
return R.success("用户名或密码错误")
router = APIRouter(tags=["Auth"]) 里的 tags 会在 Swagger UI 里分组,类似给 Controller 加 @Tag。
学习项目里密码写死、密钥写 "secret" 都可以理解;对照 Spring Security,你会知道上线要换 密码编码、密钥外置、HTTPS 等,思路是通的。
流式响应:StreamingResponse 与异步生成器
下面这段演示 按片段输出,用 StreamingResponse + async def + yield。可以类比 Spring WebFlux 的 Flux<String> 流式返回,或 MVC 里 SseEmitter / 流式 ResponseBody,只是 Python 这边用 异步生成器 写起来很直接。
# 20:24:controller/AboutController.py
@router.get("/about", response_class=StreamingResponse)
async def stream_story() -> AsyncIterable[str]:
for line in message:
await asyncio.sleep(0.01)
yield line
response_class=StreamingResponse 指明响应按「流」处理;yield line 在异步函数里构成 async generator,适合边生成边推给客户端(例如打字机效果、日志流、大模型 token 流)。
和 Spring Boot 对照的一张表
| Spring Boot 里你熟悉的 | FastAPI / 本项目里 |
|---|---|
@SpringBootApplication + 内嵌容器 |
app = FastAPI() + Uvicorn 等 ASGI 服务器运行 |
@RestController + @GetMapping / @PostMapping |
APIRouter + @router.get / @router.post |
@RequestBody DTO |
函数参数类型写成 Pydantic BaseModel |
Result<T> / 统一包装 |
R.success / R.error + R 实例字段 |
ResourceHandler 静态资源 |
app.mount("/static", StaticFiles(...)) |
| Springdoc / Swagger | 访问 /docs(Swagger UI) |
小结
对「只懂一点 Python」的 Spring 开发者来说,FastAPI 的门槛主要在 习惯缩进、模块与 router 的组织方式,以及 Pydantic 与类型标注;业务概念上 路由、DTO、统一返回、JWT、静态资源、流式响应 都能一一对应。把上面的关键代码跑通,再打开浏览器访问 /docs 试几次请求,就算是扎实的初体验了。
评论