百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

高级 FastAPI 模式:使用 Python 构建可用于生产的 API

itomcoil 2025-03-14 18:07 27 浏览

FastAPI 以其现代的异步优先方法彻底改变了 Python API 开发。我花了大量时间研究 FastAPI,我将分享在生产环境中行之有效的高级模式。

依赖注入

FastAPI 中的依赖注入提供了清晰的关注点分离和高效的资源管理。以下是数据库依赖项的实际实现:

from fastapi import Depends
from sqlalchemy.orm import Session
from contextlib import contextmanager

class Database:
    def __init__(self):
        self.session = None

    @contextmanager
    def get_session(self):
        session = Session()
        try:
            yield session
        finally:
            session.close()

db = Database()

async def get_db():
    with db.get_session() as session:
        yield session

@app.get("/users/{user_id}")
async def get_user(user_id: int, db: Session = Depends(get_db)):
    return db.query(User).filter(User.id == user_id).first()

响应缓存

实现 Redis 缓存可显著提高 API 性能。以下是一个强大的缓存实现:

from fastapi_cache import FastAPICache
from fastapi_cache.backends.redis import RedisBackend
import pickle

class CustomRedisBackend(RedisBackend):
    async def get(self, key: str):
        value = await self.redis.get(key)
        if value:
            return pickle.loads(value)
        return None

    async def set(self, key: str, value: any, expire: int = None):
        value = pickle.dumps(value)
        await self.redis.set(key, value, expire)

@app.on_event("startup")
async def startup():
    redis = aioredis.Redis(host='localhost', port=6379)
    FastAPICache.init(CustomRedisBackend(redis), prefix="fastapi-cache:")

@app.get("/products/{product_id}")
@FastAPICache.cache(expire=300)
async def get_product(product_id: int):
    return {"product_id": product_id}

后台任务

有效地管理长时间运行的操作至关重要。以下是处理后台任务的模式:

from fastapi import BackgroundTasks
from celery import Celery

celery_app = Celery('tasks', broker='redis://localhost:6379/0')

@celery_app.task
def process_video(video_id: int):
    # Video processing logic
    pass

@app.post("/videos/")
async def upload_video(
    video: UploadFile,
    background_tasks: BackgroundTasks
):
    video_id = save_video(video)
    background_tasks.add_task(process_video.delay, video_id)
    return {"status": "processing"}

速率限制

保护 API 资源需要有效的速率限制。以下是基于 Redis 的实现:

from fastapi import HTTPException
import time

class RateLimiter:
    def __init__(self, redis_client, limit: int, window: int):
        self.redis = redis_client
        self.limit = limit
        self.window = window

    async def is_allowed(self, key: str) -> bool:
        current = int(time.time())
        window_start = current - self.window

        async with self.redis.pipeline() as pipe:
            pipe.zremrangebyscore(key, 0, window_start)
            pipe.zadd(key, {str(current): current})
            pipe.zcard(key)
            pipe.expire(key, self.window)
            results = await pipe.execute()

        return results[2] <= self.limit

@app.get("/api/resource")
async def get_resource(
    redis: Redis = Depends(get_redis),
    user: User = Depends(get_current_user)
):
    rate_limiter = RateLimiter(redis, limit=100, window=3600)
    if not await rate_limiter.is_allowed(f"rate_limit:{user.id}"):
        raise HTTPException(status_code=429, detail="Rate limit exceeded")
    return {"data": "resource"}

自定义中间件

中间件提供了强大的请求/响应修改功能:

from fastapi import Request
from fastapi.middleware.base import BaseHTTPMiddleware
import time

class TimingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        start_time = time.time()
        response = await call_next(request)
        process_time = time.time() - start_time
        response.headers["X-Process-Time"] = str(process_time)
        return response

app.add_middleware(TimingMiddleware)

API 版本控制

维护 API 版本对于向后兼容性至关重要:

from fastapi import APIRouter

v1_router = APIRouter(prefix="/v1")
v2_router = APIRouter(prefix="/v2")

@v1_router.get("/users/{user_id}")
async def get_user_v1(user_id: int):
    return {"version": "1", "user_id": user_id}

@v2_router.get("/users/{user_id}")
async def get_user_v2(user_id: int):
    return {"version": "2", "user_id": user_id}

app.include_router(v1_router)
app.include_router(v2_router)

错误处理

一致的错误处理提高了 API 的可靠性:

from fastapi import HTTPException
from fastapi.responses import JSONResponse

class CustomException(Exception):
    def __init__(self, message: str, code: str):
        self.message = message
        self.code = code

@app.exception_handler(CustomException)
async def custom_exception_handler(request, exc):
    return JSONResponse(
        status_code=400,
        content={
            "error": {
                "code": exc.code,
                "message": exc.message
            }
        }
    )

@app.get("/items/{item_id}")
async def get_item(item_id: int):
    if item_id < 0:
        raise CustomException(
            message="Invalid item ID",
            code="INVALID_ID"
        )
    return {"item_id": item_id}

测试

全面的测试确保API的可靠性:

from fastapi.testclient import TestClient
import pytest

client = TestClient(app)

@pytest.fixture
def test_db():
    # Setup test database
    db = Database()
    yield db
    # Cleanup

def test_read_item():
    response = client.get("/items/1")
    assert response.status_code == 200
    assert response.json() == {"item_id": 1}

def test_create_item():
    response = client.post(
        "/items/",
        json={"name": "Test Item"}
    )
    assert response.status_code == 201

生产部署

对于生产部署,请考虑以下配置:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn

app = FastAPI(
    title="Production API",
    description="Production-ready FastAPI application",
    version="1.0.0",
    docs_url="/documentation",
    redoc_url=None
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://allowed-domain.com"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

if __name__ == "__main__":
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        workers=4,
        log_level="info",
        reload=False
    )

这些模式构成了强大的 FastAPI 应用程序的基础。异步功能与适当的资源管理和错误处理相结合,可创建高性能 API。定期测试和监控可确保生产环境中的可靠性。

请记住根据特定要求和规模调整这些模式。FastAPI 的灵活性允许自定义,同时保持性能和代码清晰度。

相关推荐

MySQL中的MVCC到底能不能解决幻读

在MySQL当中,只有使用了InnoDB存储引擎的数据库表才支持事务。有了事务就可以用来保证数据的完整以及一致性,保证成批的SQL语句要么全部执行,要么全部不执行。事务用来管理insert、updat...

每次写SQL时总忘记语法顺序怎么办,这里一招教你解决

MySQL基础(五)-----表达式&函数和分组查询表达式和函数:表达式就是将数字和运算符连接起来的组合,称之为表达式,比如:1+1;函数就是系统自带已经定义好可以直接使用的函数,例如MAX,MIN;...

在 MySQL 中使用 UUID 作为主键的存在问题及如何优化?

在分布式架构中,UUID(通用唯一标识符)因其能够确保全球唯一性而广泛应用。它不依赖于数据库的自增机制,特别适合于多个系统间的数据同步。然而,尽管UUID提供了很多优势,直接使用它作为MySQL...

SQL入门知识篇_sql入门教程

一、什么是数据库?什么是SQL?1、数据库:存放数据,可以很多人一起使用2、关系数据库:多张表+各表之间的关系3、一张表需要包含列、列名、行4、主键:一列(或一组列),其值能够唯一区分表中的每个行。5...

MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)

目录1.索引基础2.索引类型2.1哈希索引2.2有序数组2.3B+树索引(InnoDB)3.联合索引4.最左前缀原则5.覆盖索引6.索引下推总结:1.索引基础索引对查询的速度有着至...

Mysql索引覆盖_mysql索引ref

作者:京东零售孙涛1.什么是覆盖索引通常情况下,我们创建索引的时候只关注where条件,不过这只是索引优化的一个方向。优秀的索引设计应该纵观整个查询,而不仅仅是where条件部分,还应该关注查询所包...

MySQL常用语句汇总_mysql常用语句大全

一、背景日常测试开发工作中会用到各类SQL语句,很多时候都是想用的时候才发现语句细节记不清楚了,临时网上搜索SQL语法,挺费时费力的,语法还不一定是对的。因此汇总整理了一下MySQL最常用的各类语句,...

POI批量生成Word文档表格_poi批量导入excel

  前言  当我们在写设计文档,或者是其他涉及到数据架构、表结构时,可以用POI来批量生成表格,例如下面的表格  代码编写  引入POI依赖<!--引入apachepoi-...

cmd命令操作Mysql数据库,命令行操作Mysql

Mysql数据库是比较流行的数据库之一,维基百科的介绍如下:MySQLisanopen-sourcerelationaldatabasemanagementsystem(RDBMS)....

MySQL大数据表处理策略,原来一直都用错了……

场景当我们业务数据库表中的数据越来越多,如果你也和我遇到了以下类似场景,那让我们一起来解决这个问题。数据的插入,查询时长较长后续业务需求的扩展,在表中新增字段,影响较大表中的数据并不是所有的都为有效数...

SQL点滴(查询篇):数据库基础查询案例实战

本文主要是对微头条SQL小技能的汇总,便于收藏查阅,为数据库初学者提供多快好省又可实际操作的帮助。下面为正文。1.通用*查询在从数据库表中检索所有行与列,若要查询所有数据,通常做法为:select*...

Mysql学习笔记-InnoDB深度解析_mysql innodb底层原理

前言我们在上一篇博客聊了Mysql的整体架构分布,连接层、核心层、存储引擎层和文件系统层,其中存储引擎层作为MysqlServer中最重要的一部分,为我们sql交互提供了数据基础支持。存储引擎和文件...

「MySQL调优」大厂MySQL性能优化实战讲解

WhyPerformance在1990s,人们还使用拨号接入互联网的时候,浏览一个网页或加入一个线上聊天室需要几分钟的时间去加载是一件很正常的事情。而2009年Akamai公司的报告显示,如果一个网...

MySQL数据库性能优化_mysql数据库优化及sql调优

任何软件平台的运行都需要依赖于数据库的存储,数据库存储着业务系统的关键信息,包含基础的组织、人员及业务流程板块信息等。因此在平台运转过程中,数据库的响应速率直接影响平台的回显速度及用户的友好体验。尽管...

面试中的老大难-mysql事务和锁,一次性讲清楚

什么是事务在维基百科中,对事务的定义是:事务是数据库管理系统(DBMS)执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。事务的四大特性事务包含四大特性,即原子性(Atomicity)、一致性...