• Python框架篇(1):FastApi-快速入门


    1.介绍

    前言: 不管学什么语言,都应该至少掌握一个框架,方面我们后续,进行服务部署、服务对外支持等;

    1.1 官网介绍

    下面是来自FastAPI官网的介绍:

    FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 3.8+ 并基于标准的 Python 类型提示。

    关键特性:

    • 快速:可与 NodeJSGo 并肩的极高性能(归功于 Starlette 和 Pydantic)。最快的 Python web 框架之一

    • 高效编码:提高功能开发速度约 200% 至 300%。

    • 更少 bug:减少约 40% 的人为(开发者)导致错误。

    • 智能:极佳的编辑器支持。处处皆可自动补全,减少调试时间。

    • 简单:设计的易于使用和学习,阅读文档的时间更短。

    • 简短:使代码重复最小化。通过不同的参数声明实现丰富功能。bug 更少。

    • 健壮:生产可用级别的代码。还有自动生成的交互式文档。

    • 标准化:基于(并完全兼容)API 的相关开放标准:OpenAPI (以前被称为 Swagger) 和 JSON Schema

    • 官方文档:https://fastapi.tiangolo.com/zh/

    1.2 Github热度

    框架Star开源地址
    django73.9khttps://github.com/django/django
    flask64.9Khttps://github.com/pallets/flask
    fastapi64.3Khttps://github.com/tiangolo/fastapi

    关于选框架一事,每个人的见解都不一样,这里不做比较,简单陈述下,我之所以选择这个框架的原因:

    • 号称和 Go并肩的极高性能, 想体验下;
    • 框架和之前两个对比,相对比较年轻,从 Github star数来看,成长热度挺好;
    • 官方文档中文支持较好,看着也比较完善;

    2.依赖安装

    @注意: fastapi有版本要求,需要的Python版本至少是Python 3.8

    2.1 安装fastapi

    # 使用pip安装
    $ pip install fastapi
    • 1

    2.2 安装ASGI 服务器

    ASGI是异步网关协议接口,一个介于网络协议服务和 Python 应用之间的标准接口,能够处理多种通用的协议类型,包括 HTTP,HTTP2 WebSocket

    pip install "uvicorn[standard]"
    • 1

    这里简单了解下什么是uvicorn :

    Uvicorn是一个基于ASGI(Asynchronous Server Gateway Interface)的异步Web服务器,用于运行异步Python web应用程序。它是由编写FastAPI框架的开发者设计的,旨在提供高性能和低延迟的Web服务;

    3. 快速启动

    3.1 编写代码

    main.py

    from fastapi import FastAPI

    app = FastAPI()

    @app.get("/")
    async def index():
        """
        注册一个根路径
        :return:
        """

        return {"message""Hello World"}


    @app.get("/info")
    async def info():
        """
        项目信息
        :return:
        """

        return {
            "app_name""FastAPI框架学习",
            "app_version""v0.0.1"
        }
    • 1

    3.2 启动服务

    ➜ uvicorn main:app --reload
    INFO:     Will watch for changes in these directories: ['/Users/liuqh/ProjectItem/PythonItem/fast-use-ai']
    INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
    INFO:     Started reloader process [11629] using WatchFiles
    INFO:     Started server process [11631]
    INFO:     Waiting for application startup.
    INFO:     Application startup complete.
    • 1

    启动命令uvicorn main:app --reload中的app,指的是app = FastAPI()变量,也可以是其他自己定义的名称;

    1.启动步骤分析:

    • 第一步: 导入 FastAPI( from fastapi import FastAPI),可以把 FastAPI理解为是 API 提供所有功能的 Python 类;
    • 第二步: 创建 FastAPI 实例( app = FastAPI()),实例化一个类,变量 appFastAPI类实例
    • 第三步: 使用 @app.get注册路由,其中 appFastAPI 类实例变量名,也可以是其他;除了 @app.get之外还支持: @app.post、@app.put、@app.delete..等方法;
    • 第四步: 使用 uvicorn启动服务;

    3.3 调试模式

    虽然通过uvicorn启动服务很方便,但有时候我们需要debug本地程序,方便问题排查,FastAPI也支持传统启动方式;修改main.py文件,追加以下代码:

    ...
    if __name__ == "__main__":
        uvicorn.run(app, host="0.0.0.0", port=8000)
    • 1

    Debug模式启动后,就可以打断点进行代码调试,具体使用方法可参考官方文档:https://fastapi.tiangolo.com/zh/tutorial/debugging

    4.访问服务

    4.1 访问接口

    alt

    4.2 访问文档

    FastApi框架在启动时,除了注册路由之外,还会自动生成API在线文档,并且生成两种在线文档: Swagger UIReDoc,访问地址分别为:

    • SwaggerUi风格文档: http://127.0.0.1:8000/docs
    • ReDoc风格文档: http://127.0.0.1:8000/redoc
    alt

    1.如何关闭文档生成?

    如果不想生成交互式文档,可以通过以下方式实例化FastAPI:

    # docs_url=None: 代表关闭SwaggerUi
    # redoc_url=None: 代表关闭redoc文档
    app = FastAPI(docs_url=None, redoc_url=None)
    • 1

    4.3 访问OpenAPI

    FastAPI框架内部实现了OpenAPI 规范,通过访问 http://127.0.0.1:8000/openapi.json,我们可以看到整个项目的 API对应的JSON描述信息,如下:

    {
        "openapi""3.1.0",
        "info": {
            "title""FastAPI",
            "version""0.1.0"
        },
        "paths": {
            "/": {
                "get": {
                    "summary""Index",
                    "description""注册一个根路径\n:return:",
                    "operationId""index__get",
                    "responses": {
                        "200": {
                            "description""Successful Response",
                            "content": {
                                "application/json": {
                                    "schema": {}
                                }
                            }
                        }
                    }
                }
            },
            "/info": {
                "get": {
                    "summary""Info",
                    "description""项目信息\n:return:",
                    "operationId""info_info_get",
                    "responses": {
                        "200": {
                            "description""Successful Response",
                            "content": {
                                "application/json": {
                                    "schema": {}
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    • 1

    5.目录结构

    5.1 官方示例目录结构

    通常我们开发一个Python服务,都不会将所有代码放到一个文件里,就像我们不会把衣服、鞋子、袜子、食物这些统统装到一个麻袋里一样; 而是会根据功能或者其他规则,分类存放,FastAPI为我们提供了一个模板,具体如下:

    .
    ├── app                  # 「app」是一个 Python 包
    │   ├── __init__.py      # 这个文件使「app」成为一个 Python 包
    │   ├── main.py          # 「main」模块,例如 import app.main
    │   ├── dependencies.py  # 「dependencies」模块,例如 import app.dependencies
    │   └── routers          # 「routers」是一个「Python 子包」
    │   │   ├── __init__.py  # 使「routers」成为一个「Python 子包」
    │   │   ├── items.py     # 「items」子模块,例如 import app.routers.items
    │   │   └── users.py     # 「users」子模块,例如 import app.routers.users
    │   └── internal         # 「internal」是一个「Python 子包」
    │       ├── __init__.py  # 使「internal」成为一个「Python 子包」
    │       └── admin.py     # 「admin」子模块,例如 import app.internal.admin
    • 1

    具体代码组织可以参考 更大的应用 - 多个文件: https://fastapi.tiangolo.com/zh/tutorial/bigger-applications/

    5.2 自定义目录结构

    个人感觉官方推荐的目录结构过于简单,和工作中经常使用的其他语言框架目录结构出入过大,所以进行了自定义修改,也是为了适应自己的开发习惯,具体修改后目录如下:

    ├── README.md  #项目介绍
    ├── app
    │   ├── __init__.py
    │   ├── config  # 配置相关
    │   │   └── __init__.py
    │   ├── constant  # 常量相关
    │   │   └── __init__.py
    │   ├── dao # 封装查询数据的方法
    │   │   └── __init__.py
    │   ├── dependencies  # 封装被依赖函数
    │   │   └── __init__.py
    │   ├── middleware # 中间件
    │   │   └── __init__.py
    │   ├── models # 数据模型文件,和表结构对应
    │   │   └── __init__.py
    │   ├── router # 路由也可以理解controller
    │   │   ├── __init__.py
    │   │   ├── default_router.py # 默认接口
    │   │   └── demo_router.py # 演示接口
    │   ├── parameter # 声明参数对应的Pydantic模型
    │   │   └── __init__.py
    │   ├── service # 就具体业务实现逻辑
    │   │   └── __init__.py
    │   └── utils # 工具类
    │       ├── __init__.py
    │       └── str_util.py
    ├── main.py # 主文件
    ├── requirements.txt #依赖文件
    ├── tests # 单元测试目录
        ├── __init__.py
        └── local_test.py
    • 1

    a.__init__.py文件的作用:

    • 标识包目录: 当Python解释器遇到一个目录中包含 __init__.py 文件时,它会将该目录识别为一个包。这样可以通过导入包的方式来组织和访问模块。 在Python3中,__init__.py 不再是创建包的唯一方式

    • 初始化包: __init__.py 文件在包被导入时会被执行,可以用于初始化包级别的变量、设置环境或执行其他必要的初始化操作。

    • 命名空间包含: 通过在 __init__.py 中定义变量、函数或类,可以将它们添加到包的命名空间中,使得在导入包时可以直接访问这些元素。

    • 避免名称冲突: 如果包目录中有与包同名的模块,导入包时可能会出现冲突。__init__.py 可以通过定义__all__变量来控制导入时的名称空间。

      # __init__.py
      __all__ = ['module1''module2']
      • 1

      这样导入包时,只有在 __all__ 中列出的模块会被导入,避免了潜在的名称冲突

    6. 路由加载

    6.1 路由文件

    假如我们在app/router目录下有以下几个文件:

    ➜  tree -L 2 app/router  -I "__pycache__"
    app/router
    ├── __init__.py
    ├── default_router.py
    └── demo_router.py
    • 1

    每个路由文件里面的编辑流程和逻辑基本一样,这里以default_router.py为例,代码如下:

    # 导入APIRouter
    from fastapi import APIRouter
    # 实例化APIRouter实例
    router = APIRouter(tags=["默认路由"])
    # 注册具体方法
    @router.get("/")
    async def index():
        """
        默认访问链接
        """

        return {
            "code"200,
            "msg""Hello World!"
        }
    • 1

    6.2 官方加载示例

    文档地址: https://fastapi.tiangolo.com/zh/tutorial/bigger-applications/#fastapi

    在主体文件main.py中,代码如下:

    from fastapi import Depends, FastAPI
    ...
    # 从routers导出路由文件:items, users
    from .routers import items, users

    # 挨个注册文件
    app.include_router(users.router)
    app.include_router(items.router)
    app.include_router(
        admin.router,
        prefix="/admin",
        tags=["admin"],
        dependencies=[Depends(get_token_header)],
        responses={418: {"description""I'm a teapot"}},
    )
    @app.get("/")
    async def root():
        return {"message""Hello Bigger Applications!"}

    • 1

    6.2 优化导入

    1.编辑app/router/__init__.py
    from app.router import default_router, demo_router

    # 定义路由列表
    RegisterRouterList = [
        default_router,
        demo_router
    ]
    • 1

    __init__.py中定义变量,把要注册的路由统一放在列表中,然在main.py中通过循环加载路由;后续有新增路由时,直接在列表中新增元素即可;

    2.修改main.py
    import uvicorn
    from fastapi import FastAPI
    from app.router import RegisterRouterList

    # 实例化
    app = FastAPI()
    # 加载路由 
    for item in RegisterRouterList:
        app.include_router(item.router)

    if __name__ == "__main__":
        uvicorn.run(app, host="0.0.0.0", port=8000)
    • 1

    本文由 mdnice 多平台发布

  • 相关阅读:
    Spring底层架构核心概念
    Java基础面试,接口和抽象类的区别?
    解决Python获取串口数据只能获取一部分的问题
    cocos creator做圆形进度条
    Vue 3 打印解决方案:Vue-Plugin-HiPrint
    论文数据去哪找?
    企业级java笔试题,面试题第二篇
    15位、7位可控字符下的任意命令执行
    美军2分钟快速入睡法
    华为发布应用流程
  • 原文地址:https://blog.csdn.net/weixin_39001207/article/details/134427293