fastapi教程(一):初识 fastapi

news2024/11/26 1:32:52

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

关键特性:

  • 快速:可与 NodeJS 和 Go 并肩的极高性能(归功于 Starlette 和 Pydantic)。最快的 Python web 框架之一。
  • 高效编码:提高功能开发速度约 200% 至 300%。
  • 更少 bug:减少约 40% 的人为(开发者)导致错误。
  • 智能:极佳的编辑器支持。处处皆可自动补全,减少调试时间。
  • 简单:设计的易于使用和学习,阅读文档的时间更短。
  • 简短:使代码重复最小化。通过不同的参数声明实现丰富功能。bug 更少。
  • 健壮:生产可用级别的代码。还有自动生成的交互式文档。
  • 标准化:基于(并完全兼容)API 的相关开放标准:OpenAPI (以前被称为 Swagger) 和 JSON Schema。

简单来体验一下:
环境:

  • Python 3.11
  • Windows 10
  • fastapi 0.68.0

1,安装 fastapi

pip install fastapi

2,安装一个 ASGI 服务器

pip install "uvicorn[standard]"
  • 生产环境可以使用 Uvicorn 或者 Hypercorn。

ASGI(Asynchronous Server Gateway Interface)是 Python 异步服务器网关接口的缩写。
它定义了异步编程风格的 Python Web 服务器与 Web 服务器和应用程序之间的标准接口。
ASGI 旨在解决传统 Python Web 服务器(如WSGI)在高并发和长连接场景下的不足,使用异步编程模型来提高服务器的并发处理能力。
ASGI服务器具有以下几个关键特点:

  • 异步和事件驱动:ASGI 服务器采用异步非阻塞的编程模型,可以高效处理大量并发连接,避免进程/线程阻塞。它使用事件循环机制,在有事件到来时处理,否则释放资源做其他事情。
  • 支持长连接和WebSocket:ASGI 服务器本身支持长连接和 WebSocket 协议,可用于构建实时通信应用,如在线聊天室、协作平台等。
    标准统一接口:ASGI 定义了统一的服务器端接口规范,使Web服务器、中间件和应用程序之间松散耦合,易于拓展和维护。
    高性能:相比传统 WSGI,ASGI 编程模型使用异步协程可以大幅降低上下文切换和内存开销,从而提高并发性能。

目前支持 ASGI 的服务器有 Uvicorn、Daphne、Hypercorn 等,应用框架包括 Django Channels、FastAPI 等。ASGI 正在逐渐取代 WSGI 成为 Python Web 应用开发的新标准,特别适合于需要高并发、实时双向通信的应用场景。

3,创建一个 main.py 文件

from typing import Union

from fastapi import FastAPI

# 创建 FastAPI 实例
app = FastAPI()

# 定义路由,处理 get 请求
@app.get("/")
# 定义路由处理函数
async def read_root():
    return {"Hello": "World"}

# 定义路由,处理 get 请求,接收一个路径参数 item_id
@app.get("/items/{item_id}")
async def read_item(
        item_id: int,
        q: str = 'default',
):
    return {"item_id": item_id, "q": q}

4,运行项目

$ uvicorn main:app --reload
INFO:     Will watch for changes in these directories: ['I:\\Python\\Web\\FastAPI\\fastApiProject1']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [14776] using WatchFiles
INFO:     Started server process [24944]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
  • main:main.py 文件(一个 Python “模块”)。
  • app:在 main.py 文件中通过 app = FastAPI() 创建的对象。
  • –reload:让服务器在更新代码后重新启动。仅在开发时使用该选项。

5,浏览器访问路由

访问 http://127.0.0.1:8000/ 可以在页面看到路由处理函数返回的数据:
在这里插入图片描述
访问 http://127.0.0.1:8000/items/5?q=somequery 可以在页面看到路由处理函数返回的数据:
在这里插入图片描述

6,体验类型声明的优势

浏览器访问 http://127.0.0.1:8000/docs 可以到达 API 界面:
在这里插入图片描述

但是国内可能打不开。
fastapi访问/docs和/redoc接口文档显示空白或无法加载
FastAPI 自动文档Swagger UI 打不开。显示空白

打开这个页面,我们可以看到非常详细的 API 描述:
在这里插入图片描述

  • item_id:integer类型,是一个路径参数,而且是必需的。
  • q:string 类型,是一个查询参数,而且不是必需的。

这是怎么做到的?回到代码:

@app.get("/items/{item_id}")
def read_item(
        item_id: int,
        q: str = 'default',
):
    return {"item_id": item_id, "q": q}

路由装饰器中定义了路径 /items/{item_id},路径参数 item_id 在路由处理函数中明确定义为 int 数据类型,且未指定默认值,路径参数是用户必须传递的

路由处理函数中,q 明确定义为 str 数据类型,且赋予了一个默认值 default,这种不是路径参数的路由处理函数参数就是查询参数

  • 把默认值设为 None 即可声明可选的查询参数

最重要的特征就是,我们为参数添加了类型声明,这样做有非常多好处:

  1. 由 FastAPI 通过类型声明自动将解析请求中的字符串转为声明的数据类型:
    在这里插入图片描述
    2,更方便地利用编辑器的自动提示:
    在这里插入图片描述

7,借助 Pydantic 完成数据验证

多数情况我们会用 POST(最常用)、PUT 操作来发送数据,具体就是将数据放在这些请求的请求体中。
既然路径参数和查询参数都可以通过定义数据类型来完成默认的类型转化和校验,那么作为传述数据主要载体的请求体,自然也支持数据类型的定义带来的好处,响应体也是如此!

请求体和响应体的数据定义需要使用 pandatic,这是一个流行的数据验证工具。使用 Pydantic 模型声明请求体,能充分利用它的功能和优点:

  • 以 JSON 形式读取请求体。(在必要时)把请求体转换为对应的类型
  • 校验数据:数据无效时返回错误信息,并指出错误数据的确切位置和内容
  • 把接收的数据赋值给参数 item:把函数中请求体参数的类型声明为 Item,还能获得代码补全等编辑器支持
  • 为模型生成 JSON Schema,在项目中所需的位置使用
  • 用于 API 文档 UI
from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
  • 修改代码并保存后,服务器将会自动重载(因为在上面的步骤中你向 uvicorn 命令添加了 --reload 选项来启动服务)

我们通过使继承 pydantic 的 BaseModel 类来定义了一个类,通常会将它称为模型,在这个模型中我们定义了一些字段及其数据类型,然后我们用这个模型定义一个查询参数的类型。

  • 使用Pydantic 模型的参数,是请求体。
  • 与声明查询参数一样,包含默认值的模型属性是可选的,否则就是必选的。默认值为 None 的模型属性也是可选的。

上述模型声明如下 JSON 对象(即 Python 字典):

{
    "name": "Foo",
    "description": "An optional description",
    "price": 45.2,
    "tax": 3.5
}

运行项目,使用接口调试工具进行调试:
在这里插入图片描述
如果请求体数据必填项缺失:

发送:
{
    "name": "Foo",
    "description": "An optional description",
    "tax": 3.5
}
返回:
{
	"detail": [
		{
			"type": "missing",
			"loc": [
				"body",
				"price"
			],
			"msg": "Field required",
			"input": {
				"name": "Foo",
				"description": "An optional description",
				"tax": 3.5
			}
		}
	]
}

如果数据类型错误:

发送:
{
    "name": "Foo",
    "description": "An optional description",
    "price": "error type",
    "tax": 3.5
}
返回:
{
	"detail": [
		{
			"type": "float_parsing",
			"loc": [
				"body",
				"price"
			],
			"msg": "Input should be a valid number, unable to parse string as a number",
			"input": "error type"
		}
	]
}

这就是 pandatic 实现请求体数据校验的最大好处!

接下来看看响应体:可以在任意的路径操作中使用 response_model 参数来声明用于响应的模型。

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app)

即便我们的路径操作函数将会返回包含密码的相同输入用户,但我们已经将 response_model 声明为了不包含密码的 UserOut 模型,FastAPI 将会负责过滤掉未在输出模型中声明的所有数据

发送:
{
    "username": "Jonas Vingegaard",
    "password": "123456",
    "email": "test@test.com",
    "full_name": "Jonas Vingegaard Rasmussen"
}
返回:
{
	"username": "Jonas Vingegaard",
	"email": "test@test.com",
	"full_name": "Jonas Vingegaard Rasmussen"
}

发送:
{
    "username": "Jonas Vingegaard",
    "password": "123456",
    "email": "test@test.com"
}
返回:
{
	"username": "Jonas Vingegaard",
	"email": "test@test.com",
	"full_name": null
}

发送:
{
    "username": "Jonas Vingegaard",
    "password": "123456"
}
返回:
{
	"detail": [
		{
			"type": "missing",
			"loc": [
				"body",
				"email"
			],
			"msg": "Field required",
			"input": {
				"username": "Jonas Vingegaard",
				"password": "123456"
			}
		}
	]
}

8,使用数据库

任何SQLAlchemy支持的数据库,如:

  • PostgreSQL
  • MySQL
  • SQLite
  • Oracle
  • Microsoft SQL Server,等等其它数据库

首先你需要安装SQLAlchemy:

pip install sqlalchemy

创建目录:

└── sql_app
    ├── __init__.py
    ├── crud.py
    ├── database.py
    ├── main.py
    ├── models.py
    └── schemas.py

定义数据库:

# sql_app/database.py

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# 为 SQLAlchemy 定义数据库 URL地址
SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"

# 创建 SQLAlchemy 引擎
engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)

# 创建一个SessionLocal类
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 创建一个Base类
Base = declarative_base()

创建数据库模型:

# sql_app/models.py

from sqlalchemy import Boolean, Column, ForeignKey, Integer, String

from sql_app.database import Base


class User(Base):
    __tablename__ = "users"
    __table_args__ = {'extend_existing': True}

    id = Column(Integer, primary_key=True)
    email = Column(String, unique=True)
    hashed_password = Column(String)
    is_active = Column(Boolean, default=True)

创建 Pydantic 模型:

# sql_app/schemas.py

from pydantic import BaseModel


class UserBase(BaseModel):
    email: str


class UserCreate(UserBase):
    password: str


class User(UserBase):
    id: int
    is_active: bool

    class Config:
        orm_mode = True

主程序——controller:

# main.py

from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session
from sql_app import crud, models, schemas
from sql_app.database import SessionLocal, engine

models.Base.metadata.create_all(bind=engine)

app = FastAPI()


# Dependency
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


@app.post("/users/", response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
    db_user = crud.get_user_by_email(db, email=user.email)
    if db_user:
        raise HTTPException(status_code=400, detail="Email already registered")
    return crud.create_user(db=db, user=user)


@app.get("/users/", response_model=list[schemas.User])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    users = crud.get_users(db, skip=skip, limit=limit)
    return users


@app.get("/users/{user_id}", response_model=schemas.User)
def read_user(user_id: int, db: Session = Depends(get_db)):
    db_user = crud.get_user(db, user_id=user_id)
    if db_user is None:
        raise HTTPException(status_code=404, detail="User not found")
    return db_user



if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app)

添加 crud 操作实现:

# crud.py

from sqlalchemy.orm import Session

from sql_app import models, schemas


def get_user(db: Session, user_id: int):
    return db.query(models.User).filter(models.User.id == user_id).first()


def get_user_by_email(db: Session, email: str):
    return db.query(models.User).filter(models.User.email == email).first()


def get_users(db: Session, skip: int = 0, limit: int = 100):
    return db.query(models.User).offset(skip).limit(limit).all()


def create_user(db: Session, user: schemas.UserCreate):
    fake_hashed_password = user.password + "notreallyhashed"
    db_user = models.User(email=user.email, hashed_password=fake_hashed_password)
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

去启动程序,访问 API 页面:
在这里插入图片描述
POST 创建一些数据,然后就能 GET 它们了。

9,文件的上传与下载

简单的文件上传:

from urllib.parse import quote

from fastapi import FastAPI, UploadFile
from fastapi.responses import StreamingResponse

app = FastAPI()


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    # 分块将大文件保存到磁盘
    file_object = file.file
    file_name = file.filename
    # 判断文件夹是否存在,不存在则创建
    import os
    if not os.path.exists("files"):
        os.mkdir("files")
    # 将文件写入到文件夹
    with open(f"files/{file_name}", "wb") as f:
        while True:
            # 读取文件
            chunk = file_object.read(10000)
            if not chunk:
                break
            f.write(chunk)

    return {"filename": file.filename}


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app)

大文件下载:


def file_iterator(file_path, chunk_size=8192):
    with open(file_path, mode="rb") as file_like:
        while True:
            chunk = file_like.read(chunk_size)
            if not chunk:
                break
            yield chunk


# 流式下载文件
@app.get("/downloadfile/")
async def download_file(file_name: str):
    file_path = f"files/{file_name}"
    # 判断文件是否存在
    import os
    if not os.path.exists(file_path):
        return {"msg": "file not found"}
    else:
        headers = {
            'Content-Disposition': f'attachment; filename="{quote(file_name)}"'
        }
        return StreamingResponse(
            file_iterator(file_path),
            media_type="application/octet-stream",
            headers=headers
        )

10,部署 fastapi 项目

先收集项目依赖:

pip freeze > requirements.txt

然后将项目发送到服务器。
在服务器安装 ASGI 服务器:

pip install "uvicorn[standard]"

然后运行服务器程序:

uvicorn main:app --host 0.0.0.0 --port 80

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1849258.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《窄门》情不知所起,而一往情深

《窄门》情不知所起,而一往情深 安德烈纪德(1869-1951),法国作家。纪德一生著有小说、剧本、论文、散文、日记、书信多种,主要作品有小说《背德者》《窄门》《田园交响曲》《伪币制造者》等,戏剧《康多尔王…

莱辅络Rebro BIM机电专业软件

莱辅洛(Rebro)是一款专业机电 BIM 软件。它具备专业人士所期待的各种专业功能,应用于建筑机电工程的三维设计,并且适用于建筑、结构、给排水、暖通、电气五大专业。 该软件具有以下特点: • 3D 模型:可以…

R语言——数据结构与数据处理

1、练习使用seq( )函数创建向量:使用3种方法生成0~1,步长为0.1的向量,并在控制台打印出来。 2、练习使用rep( )函数创建向量:(1)生成一个4个元素均为3的向量;(2)生成一个…

C语言 | Leetcode C语言题解之第165题比较版本号

题目&#xff1a; 题解&#xff1a; int compareVersion(char * version1, char * version2){int len1 strlen(version1);int len2 strlen(version2);int i 0;int j 0;while (i < len1 || j < len2) {int num1 0;int num2 0;while (i < len1 && versio…

Android记录19-朋友圈动态发布时间计算

注意这里要1&#xff0c;因为月份是从0开始的。 获取当前月的第几天&#xff1a; calendar.get(Calendar.DAY_OF_MONTH) 获取当前时间毫秒显示&#xff1a; calendar.getTimeInMillis() Calendar还可以做很多一些运算&#xff0c;笔者在开发日历控件的时候&#xff0c;就做…

与Vatee万腾平台同行,共创智能未来

在科技日新月异的今天&#xff0c;智能化已成为推动社会进步的重要力量。Vatee万腾平台&#xff0c;作为这一浪潮中的佼佼者&#xff0c;正以其独特的创新力和前瞻的视野&#xff0c;引领我们迈向智能未来。与Vatee万腾平台同行&#xff0c;我们不仅能享受到科技带来的便捷与舒…

02 Shell编程之条件语句

1、条件测试操作 要使Shell脚本程序具备一定的智能&#xff0c;面临的第一个问题就是如何区分不同的情况以确定执行何种操作。 例如&#xff0c;当磁盘使用率超过95%时&#xff0c;发送告警信息&#xff1b;当备份目录不存在时&#xff0c;能够自动创建&#xff1b; 当源码编…

广东省建筑施工安管人员考核报名流程及照片处理方法

广东省建筑施工企业安管人员考核工作现已全面启动&#xff0c;这对于提升建筑行业的安全生产管理水平至关重要。为了确保广大考生能够顺利报名并参与考核&#xff0c;本文精心梳理了考核报名流程&#xff0c;并提供了证件照的规范处理方法。同时&#xff0c;针对证件照这一关键…

Java23种设计模式(四)

1、备忘录模式 备忘录模式&#xff08;Memento Pattern&#xff09;保存一个对象的某个状态&#xff0c;以便在适当的时候恢复对象&#xff0c;备忘录模式属于行为型模式。 备忘录模式允许在不破坏封装性的前提下&#xff0c;捕获和恢复对象的内部状态。 实现方式 创建备忘录…

Star、Star求Star

本章是介绍博主自己的一个小工具的。使用的PythonPyQt5开发的。顺带来求一波star&#x1f31f;&#x1f31f;&#xff01;&#xff01;&#xff01; 地址&#xff1a;https://gitee.com/qinganan_admin/PyCom Pycom是博主开发的串口工具&#xff0c;要是说对比其他串口工具&…

Apache HTTP server benchmarking tool(ab)-服务器基准测试工具一文上手

这是一个非常简单的工具&#xff0c;用途比较有限&#xff0c;只能针对单个URL进行尽可能快的压力测试。 ​ Windows下如何下载安装&#xff08;Linux安装十分简单&#xff09; Apache HTTP server benchmarking tool(ab)下载地址 ​ 资源 2.4版本 httpd-2.4.48-o111k-x64…

【FreeRTOS】创建任务_使用任务参数

参考《FreeRTOS入门与工程实践(基于DshanMCU-103).pdf》 文章目录 前言编写任务函数创建任务任务保护措施写了个bug疑问遗留问题效果freertos.c 学习链接 前言 配套源码&#xff1a;06_create_task_use_params 我们创建3个任务&#xff0c;使用同一个函数&#xff0c;但是在L…

【昇思初学入门】第三天打卡

数据集Dataset 心得体会 昇思提供了丰富的数据集&#xff0c;文本、图像、音频等都有内置MindSpore的Pipeline设计和并行处理能力使得数据预处理更加高效可通过GeneratorDataset接口实现自定义方式的数据集加载可迭代的数据集&#xff0c;可以通过迭代的方式逐步获取数据样本…

【进阶篇-Day4:使用JAVA编写石头迷阵游戏】

目录 1、绘制界面2、打乱石头方块3、移动业务4、游戏判定胜利5、统计步数6、重新游戏7、完整代码&#xff1a; 1、绘制界面 上述思路是&#xff1a;使用一个二维数组存放图片的编号&#xff0c;然后在后持遍历即可获取对应的图片。 代码如下&#xff1a; package com.itheima.s…

异步FIFO

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 请根据题目中给出的双口RAM代码和接口描述&#xff0c;实现异步FIFO&#xff0c;要求FIFO位宽和深度参数化可配置。 电路的接口如下图所示。 双口RAM端口说明&#xff1a; 端口名 I/O 描述 wclk i…

centos中安装并设置vsftpd

vsftpd是一个可安装在linux上的ftp服务器软件。 一、安装 安装前保证服务器能上互联网。如果不能上网&#xff0c;看看能不能设法利用局域网代理上网。 sudo yum -y install vsftpd二、配置 1、修改配置文件 cd /etc/vsftpd #修改之前记得备份&#xff01;&#xff01;&am…

D触发器(D Flip-Flop)与D锁存器(D Latch)

1 基础概念 我们先来简单回顾一下D触发器&#xff08;D flip-flop&#xff09;和D锁存器&#xff08;D latch&#xff09;的概念&#xff0c;以及它们在数字电路中的作用。 1.1 D触发器&#xff08;D Flip-Flop&#xff09; D触发器是一种数字存储器件&#xff0c;它在时钟信号…

深入理解计算机系统 CSAPP 家庭作业6.46

理解题意:G是有向图g的邻接矩阵 G[j*dim i] G[j*dim i] || G[i*dim j]; 通过i和j遍历G中的所有元素,||运算将遍历到的元素对称起来. 下面我们来优化col_convert(int *G, int dim) : void col_convert(int N, int G[N][N], int bsize) {if(bsize < 0 || bsize > N…