FastAPI-3:快速入门

news/2025/3/15 0:36:26/文章来源:https://www.cnblogs.com/testing-/p/18233400

3 快速入门

第二章是python基础,故不做介绍。

FastAPI是一个现代、快速(高性能)的网络框架,用于使用基于标准Python 类型提示的Python 3.6+构建API。
FastAPI的创建者是Sebastián Ramírez。

FastAPI由Sebastián Ramírez于2018年发布。与大多数Python Web框架相比,它在很多方面都更加现代化--充分利用了过去几年中添加到Python 3 中的功能。本章将快速介绍FastAPI的主要功能,重点是您首先需要了解的内容:如何处理Web请求和响应。

3.1 FastAPI简介

与其他网络框架一样,FastAPI 可以帮助您构建网络应用程序。每个框架的设计都是为了通过功能、遗漏和默认设置来简化某些操作。顾名思义,FastAPI的目标是开发网络API,不过您也可以将其用于传统的网络内容应用程序。

FastAPI具有以下优势:

  • 性能:在某些情况下与Node.js和Go一样快,与Python框架不同。

  • 快速开发:容易上手,简单清晰。

  • 代码质量更高:类型提示和模型有助于减少错误。

  • 自动生成文档和测试页面:比手工编辑OpenAPI说明容易得多。

FastAPI 使用以下功能:

  • Python 类型提示
  • 用于网络机制的 Starlette,包括异步支持
  • 用于数据定义和验证的 Pydantic
  • 用于利用和扩展其他工具的特殊集成

这种组合为网络应用程序(尤其是 RESTful 网络服务)提供了令人满意的开发环境。

3.2 FastAPI应用

让我们编写一个小巧的 FastAPI 应用程序--只有一个端点的网络服务。现在,我们处于我所说的网络层,只处理网络请求和响应。首先,安装我们要用到的基本 Python 包:

  • FastAPI 框架: pip install fastapi
  • Uvicorn 网络服务器: pip install uvicorn
  • HTTPie 文本网络客户端: pip install httpie
  • 请求同步网络客户端软件包: pip install requests
  • HTTPX 同步/异步网络客户端软件包: pip install httpx

虽然curl是最著名的文本网络客户端,但我认为HTTPie更容易使用。此外,它默认使用JSON编码和解码,更适合 FastAPI。在本章后面,你会看到一张截图,其中包含访问特定端点所需的curl命令行语法。

hello.py:

from fastapi import FastAPIapp = FastAPI()@app.get("/hi")
def greet():return "Hello? World?"
  • app是顶级FastAPI对象,代表整个网络应用程序。
  • @app.get("/hi") 是一个路径装饰器。它告诉 FastAPI 以下内容:
    • 在此服务器上对URL"/hi"的请求应被指向以下函数。
    • 此装饰器仅适用于 HTTP GET verb。您也可以使用其他 HTTP 动词(PUT、POST 等)来响应"/hi"URL,每个动词都有一个单独的函数。
  • def greet()是一个路径函数--HTTP 请求和响应的主要连接点。

下一步是在网络服务器中运行该网络应用程序。FastAPI本身不包含网络服务器,但推荐使用Uvicorn。您可以通过两种方式启动Uvicorn和FastAPI 网络应用程序:外部启动或内部启动。

从外部通过命令行启动Uvicorn 的方法:

$ uvicorn hello:app --reload

其中hello指的是hello.py文件,app是其中的FastAPI变量名。内部启动如下:

from fastapi import FastAPIapp = FastAPI()@app.get("/hi")
def greet():return "Hello? World?"if __name__ == "__main__":import uvicornuvicorn.run("hello:app", reload=True, host=r'0.0.0.0', port=8008)

无论哪种情况,如果hello.py发生变化,reload都会告诉 Uvicorn 重新启动网络服务器。在本章中,我们将经常使用自动重载功能。默认情况下都会使用你机器上的 8000 端口(名为 localhost)。如果你想使用其他方法,外部方法和内部方法都有主机和端口参数。
现在服务器有了一个端点(/hi),可以随时接受请求了。让我们用多个网络客户端进行测试:

  • 对于浏览器,在顶部位置栏键入URL。

  • HTTPie
$ http localhost:8008/hi
HTTP/1.1 200 OK
content-length: 15
content-type: application/json
date: Thu, 06 Jun 2024 01:41:28 GMT
server: uvicorn"Hello? World?"# 使用 -b 参数跳过响应头,只打印正文。
$ http -b localhost:8008/hi
"Hello? World?"# 使用 -v 获取完整的请求头和响应。
# http -v localhost:8008/hi
GET /hi HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:8008
User-Agent: HTTPie/3.2.2HTTP/1.1 200 OK
content-length: 15
content-type: application/json
date: Thu, 06 Jun 2024 01:51:23 GMT
server: uvicorn"Hello? World?"
  • Requests 或 HTTPX
>>> import requests
>>> r = requests.get("http://localhost:8008/hi")
>>> r.json()
'Hello? World?'
>>> import httpx
>>> r = httpx.get("http://localhost:8008/hi")
>>> r.json()
'Hello? World?'

3.3 HTTP请求

上面第一个HTTPie请求包含以下内容:

  • 动词 (GET) 和路径 (/hi)
  • 查询参数(此处为"无",有的话跟在问号后面)
  • 其他 HTTP 头信息
  • 正文内容(无请求)

FastAPI 将这些信息归纳为方便的定义:Header、Path、Query、Body。

FastAPI从HTTP请求的各个部分提供数据的方式是其最大的特点之一,也是对大多数Python Web框架的改进。您需要的所有参数都可以直接在path函数中声明和提供,使用前面列表中的定义 (Path、Query 等),以及您编写的函数。这使用了一种名为"依赖注入"的技术,我们将继续讨论这种技术,并在第 6 章中进一步阐述。

3.3.1 URL Path

让我们在前面的应用程序中添加一个名为 who 的参数,向某人发送 Hello? 我们将尝试不同的方法来传递这个新参数:

from fastapi import FastAPIapp = FastAPI()@app.get("/hi/{who}")
def greet(who):return f"Hello? {who}?"if __name__ == "__main__":import uvicornuvicorn.run("hello:app", reload=True, host=r'0.0.0.0', port=8008)

在 URL 中(@app.get 之后)添加 {who},会告诉 FastAPI 在 URL 中的该位置期待一个名为 who 的变量。然后,FastAPI 将其赋值给下面 greet() 函数中的 who 参数。这显示了路径装饰器和路径函数之间的协调。
注意不要在此处使用 Python f-string 来表示修改后的 URL 字符串 ("/hi/{who}")。

from fastapi import FastAPIapp = FastAPI()@app.get("/hi/{who}")
def greet(who):return f"Hello? {who}?"if __name__ == "__main__":import uvicornuvicorn.run("hello:app", reload=True, host=r'0.0.0.0', port=8008)

执行:


# http -b localhost:8008/hi/test
"Hello? test?"# http -b localhost:8008/hi
{"detail": "Not Found"
}

参考资料

  • 软件测试精品书籍文档下载持续更新 https://github.com/china-testing/python-testing-examples 请点赞,谢谢!
  • 本文涉及的python测试开发库 谢谢点赞! https://github.com/china-testing/python_cn_resouce
  • python精品书籍下载 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
  • Linux精品书籍下载 https://www.cnblogs.com/testing-/p/17438558.html

3.3.2查询参数

查询参数是 URL中?后面的name=value字符串,用&字符分隔。

from fastapi import FastAPIapp = FastAPI()@app.get("/hi")
def greet(who):return f"Hello? {who}?"if __name__ == "__main__":import uvicornuvicorn.run("hello:app", reload=True, host=r'0.0.0.0', port=8008)

执行:


# http localhost:8008/hi?who=Mom
HTTP/1.1 200 OK
content-length: 13
content-type: application/json
date: Thu, 06 Jun 2024 02:58:24 GMT
server: uvicorn"Hello? Mom?"# http localhost:8008/hi
HTTP/1.1 422 Unprocessable Entity
content-length: 89
content-type: application/json
date: Thu, 06 Jun 2024 02:58:31 GMT
server: uvicorn{"detail": [{"input": null,"loc": ["query","who"],"msg": "Field required","type": "missing"}]
}# 注意两个等号为GET, 冒号表示HTTP头,一个等号为POST,
# http -b localhost:8008/hi who==Mom
"Hello? Mom?"

3.3.3 POST

from fastapi import FastAPI, Bodyapp = FastAPI()@app.post("/hi")
def greet(who:str = Body(embed=True)):return f"Hello? {who}?"if __name__ == "__main__":import uvicornuvicorn.run("hello:app", reload=True, host=r'0.0.0.0', port=8000)

执行:


# /root/code/fastapi/example^C
root@www:~/code/fastapi/example# http -v localhost:8000/hi who=Mom
POST /hi HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 14
Content-Type: application/json
Host: localhost:8000
User-Agent: HTTPie/3.2.2{"who": "Mom"
}HTTP/1.1 200 OK
content-length: 13
content-type: application/json
date: Thu, 06 Jun 2024 03:25:34 GMT
server: uvicorn"Hello? Mom?"

需要使用 Body(embed=True) 来告 FastAPI,这次我们从JSON格式的请求正文中获取who的值。embed 部分意味着它看起来应该像 {"who": "Mom"},而不仅仅是 "Mom"。

3.3.4 HTTP 头信息

from fastapi import FastAPI, Headerapp = FastAPI()@app.get("/hi")
def greet(who:str = Header()):return f"Hello? {who}?"if __name__ == "__main__":import uvicornuvicorn.run("hello:app", reload=True, host=r'0.0.0.0', port=8000)

执行:

# http -v localhost:8000/hi who:Mom
GET /hi HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:8000
User-Agent: HTTPie/3.2.2
who: MomHTTP/1.1 200 OK
content-length: 13
content-type: application/json
date: Thu, 06 Jun 2024 06:09:55 GMT
server: uvicorn"Hello? Mom?"

3.3.5 多重请求数据

你可以在同一个路径函数中使用多个方法。也就是说,你可以从 URL、查询参数、HTTP 主体、HTTP 头文件、cookie等获取数据。你还可以编写自己的依赖函数,以特殊方式处理和组合这些数据,例如用于分页或身份验证。

3.3.6哪种方法最好?

以下是一些建议:

  • 在URL中传递参数时,遵循 RESTful 准则是标准做法。
  • 查询字符串通常用于提供可选参数,如分页。
  • body通常用于较大的输入,如整个或部分模型。

在每种情况下,如果您在数据定义中提供了类型提示,Pydantic就会自动对您的参数进行类型检查。这将确保参数的存在和正确性。

3.4 HTTP响应

默认情况下FastAPI会将返回的内容转换为JSON;HTTP响应的头行内容类型为:application/json。

3.4.1 状态代码

FastAPI默认返回200状态代码;异常会产生4xx代码。在路径装饰器中,指定在一切顺利的情况下应返回的 HTTP 状态代码可以改写返回(异常会生成自己的代码并覆盖它)。

from fastapi import FastAPI, Bodyapp = FastAPI()@app.post("/hi")
def greet(who:str = Body(embed=True)):return f"Hello? {who}?"if __name__ == "__main__":import uvicornuvicorn.run("hello:app", reload=True, host=r'0.0.0.0', port=8000)

执行:

~# http localhost:8000/happy
HTTP/1.1 200 OK
content-length: 4
content-type: application/json
date: Thu, 06 Jun 2024 06:39:00 GMT
server: uvicorn":)"# http localhost:8000/happy3
HTTP/1.1 404 Not Found
content-length: 22
content-type: application/json
date: Thu, 06 Jun 2024 06:40:32 GMT
server: uvicorn{"detail": "Not Found"
}

3.4.2 Headers

from fastapi import FastAPI, Body, Responseapp = FastAPI()@app.get("/header/{name}/{value}")
def header(name: str, value: str, response:Response):response.headers[name] = valuereturn "normal body"if __name__ == "__main__":import uvicornuvicorn.run("hello:app", reload=True, host=r'0.0.0.0', port=8000)

执行:

# http localhost:8000/header/marco/polo
HTTP/1.1 200 OK
content-length: 13
content-type: application/json
date: Thu, 06 Jun 2024 06:48:10 GMT
marco: polo
server: uvicorn"normal body"

3.4.3 响应类型

响应类型(从 fastapi.responses 中导入这些类)包括以下内容:

  • JSONResponse(默认值)
  • HTMLResponse
  • PlainTextResponse
  • RedirectResponse
  • FileResponse
  • StreamingResponse

关于后两种,我将在第15章中详细介绍。对于其他输出格式(也称为 MIME 类型),可以使用通用的 Response 类,它需要以下内容:

  • content:字符串或字节

  • media_type:字符串 MIME 类型

  • status_code:HTTP 整数状态代码

  • headers:字符串

3.4.4 类型转换

路径函数可以返回任何内容,默认情况下(使用 JSONResponse),FastAPI 会将其转换为 JSON 字符串并返回,同时返回与之匹配的 HTTP 响应头 Content-Length 和 Content-Type。这包括任何 Pydantic 模型类。
但它是如何做到这一点的呢?如果您使用过 Python json 库,您可能会发现,当给定某些数据类型(如日期时间)时,它会引发异常。FastAPI 使用名为 jsonable_encoder() 的内部函数将任何数据结构转换为 "JSONable" Python 数据结构,然后调用 json.dumps() 将其转换为 JSON 字符串。


import datetime
import json
import pytest
from fastapi.encoders import jsonable_encoder@pytest.fixture
def data():return datetime.datetime.now()def test_json_dump(data):with pytest.raises(Exception):_ = json.dumps(data)def test_encoder(data):out = jsonable_encoder(data)assert outjson_out = json.dumps(out)assert json_out

3.4.4 模型类型和响应模型

不同的类可能有许多相同的字段,只是一个专门用于用户输入,一个用于输出,还有一个用于内部使用。产生这些变体的原因可能包括以下几点:

  • 从输出中移除一些敏感信息,比如去识别个人医疗数据,如果你遇到《健康保险可携性和责任法案》(HIPAA)的要求。
  • 为用户输入添加字段(如创建日期和时间)。

下列展示了一个假定案例中的三个相关类:

  • TagIn 是定义用户需要提供的内容(在本例中,只是一个名为 tag 的字符串)的类。
  • Tag 是由 TagIn 生成的,并增加了两个字段:created(创建时间)和 secret(内部字符串,可能存储在数据库中,但永远不会向外界公开)。
  • TagOut 是定义可以返回给用户(通过查询或搜索终端)的内容的类。它包含来自原始 TagIn 对象及其派生 Tag 对象的标签字段,以及为 Tag 生成的创建字段,但不是秘密字段。
from datetime import datetime
from pydantic import BaseClassclass TagIn(BaseClass):tag: strclass Tag(BaseClass):tag: strcreated: datetimesecret: strclass TagOut(BaseClass):tag: strcreated: datetime

您可以通过不同方式从FastAPI路径函数返回默认JSON以外的数据类型。其中一种方法是在路径装饰器中使用 response_model 参数,让 FastAPI 返回其他类型的数据。FastAPI 将放弃任何在返回对象中存在但不在 response_model 指定的对象中的字段。

假设你编写了一个名为 service/tag.py 的新服务模块,其中包含 create() 和 get() 函数,为该网络模块提供了调用的内容。这些低层堆栈细节在这里并不重要。重要的是底部的 get_one() 路径函数,以及路径装饰器中的 response_model=TagOut。这会自动将内部 Tag 对象转换为经过消毒的 TagOut 对象。

import datetime
from fastapi import FastAPI
from model.tag import TagIn, Tag, TagOut
import service.tag as serviceapp = FastAPI()@app.post('/')
def create(tag_in: TagIn) -> TagIn:tag: Tag = Tag(tag=tag_in.tag, created=datetime.utcnow(),secret="shhhh")service.create(tag)return tag_in@app.get('/{tag_str}', response_model=TagOut)
def get_one(tag_str: str) -> TagOut:tag: Tag = service.get(tag_str)return tag

尽管我们返回的是 Tag,但response_model会将其转换为 TagOut。

3.5 自动化文档

上面3.3.3 POST的自动文档http://localhost:8000/docs。

FastAPI会根据您的代码生成一个OpenAPI规范,并包含这个页面来显示和测试您的所有端点。这只是其秘诀之一。
单击绿色框右侧的向下箭头,打开它进行测试。

点击右侧的 "试用 "按钮。现在你会看到一个区域,可以在正文部分输入数值(。

点击 "字符串"。将其更改为 "Cousin Eddie"(保留双引号)。然后单击底部的蓝色 "执行 "按钮。

3.6复杂数据

这些示例只展示了如何向端点传递单个字符串。许多端点,尤其是 GET 或 DELETE 端点,可能根本不需要参数,或者只需要几个简单的参数,如字符串和数字。但在创建(POST)或修改(PUT 或 PATCH)资源时,我们通常需要更复杂的数据结构。第 5 章展示了 FastAPI 如何使用 Pydantic 和数据模型来简洁地实现这些功能。

3.7小结

在本章中,我们使用 FastAPI 创建了一个只有一个端点的网站。多个网络客户端对其进行了测试:网络浏览器、HTTPie 文本程序、Requests Python 包和 HTTPX Python 包。从简单的 GET 调用开始,请求参数通过 URL 路径、查询参数和 HTTP 标头进入服务器。然后,HTTP 主体被用来向 POST 端点发送数据。随后,本章展示了如何返回各种 HTTP 响应类型。最后,自动生成的表单页面为第四个测试客户端提供了文档和实时表单。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

超越预期:Containerd 如何成为 Kubernetes 的首选容器运行时

> 作者:尹珉,KubeSphere Ambassado,rKubeSphere Contributor,KubeSphere 社区用户委员会杭州站站长。 踏上 Containerd 技术之旅 容器技术已经成为现代软件开发和部署的核心工具。通过容器,开发者可以创建轻量级、便携的运行环境,从而简化应用程序的开发、测试和部署流…

OPCUA 使用KEPServerEX 跟UaExper 数据不同步

UaExper,KEPServerEX 在KEPServerEX的 quick Cline里面设置的值不会同步到UaExper 里面,在UaExper上能看到设置的设备跟标记,就是修改数据时两边不同步。把具体标记拉进来view后有个报错的信息Invalid Datatype: Expected OpcUaType_Double, Received OpcUaType_UInt32 具…

MatrixTransform之相关矩阵运算

最近在学习MatrixTransform,发现对之前学的矩阵乘法竟然忘的一干二净,下面就是这个基础知识的整理。 矩阵加法 通常的矩阵加法被定义在两个相同大小的矩阵。两个mn矩阵A和B的和,标记为A+B,一样是个mn矩阵,其内的各元素为其相对应元素相加后的值。例如:也可以做矩阵的减法…

2种方法解决需要clik点击数的题目——[HNCTF 2022 WEEK2]getflag 137分 MFC patch RE

题目 DIEIDA找到判断点击数的if,我们修改一下汇编指令让点击数<99999999就成立 这个程序没有要求我们输入,说明flag是程序打印的 IDA动调下一个断点修改 得到flag 还有一种更快的方法——Cheat Engine随便点击几次 在CE中修改点击次数 Get flag flagNSSCTF{MFC_pr0gr4mmi…

2道寻找回文子串的题目

题目题目1题目2题目1是将字符串分隔,使得分隔后得到的每个字符串都是回文子串 题目2是从字符串里面找到回文子串 两道题都可以利用递归来解决 //利用双指针判断是否是回文子串 bool isre(string& s) {int left = 0;int right - s.size()-1;while(left <= right){if(s[l…

BUG:驱动新屏幕,屏幕左右无法居中

1.BUG描述 RGB屏幕的显示左右无法居中 2.BUG原因 因为屏幕参考值的前肩距和后肩距(Hfp、Hbp)的type值远远超出了芯片的限制(32、128)。所以造成左右偏移无法调节。3.修复方法 最后将屏幕的SYNC模式,硬件重新接线改为DE模式。使得前间距和后间距不再有效。4.补充 4.1 参数的计算…

密码工程-小素数

任务详情在openEuler(推荐)或Ubuntu或Windows(不推荐)中完成下面任务,使用git管理过程,至少提交三次参考《密码工程》p107伪代码基于Eratosthenes算法实现 int SmallPrimeList(int n, int *plist, int *len), 其中plist返回素数列表,len返回列表长度(5’)写出测试代码,至…

文献收获_2024.06.06

Ahmed, Syed Rakin. 2024. Generating Clinically Translatable AI Models for Cancer Diagnostics. Doctoral dissertation, Harvard University Graduate School of Arts and Sciences. 来源:https://nrs.harvard.edu/URN-3:HUL.INSTREPOS:37378697FIGURE 4 Model Zoo这部分…

高德面试:为什么Map不能插入null?

在 Java 中,Map 是属于 java.util 包下的一个接口(interface),所以说“为什么 Map 不能插入 null?”这个问题本身问的不严谨。Map 部分类关系图如下:所以,这里面试官其实想问的是:为什么 ConcurrentHashMap 不能插入 null? 1.HashMap和ConcurrentHashMap的区别 HashMa…

修改k8s pod的hosts文件

当我们服务需要使用自定义的域名解析时,就需要修改pod内hosts文件。 而如果我们在pod内部修改后,下次重启依然会丢,所有下面用两种方式实现持久化修改:1.当集群内所有或者大部分服务都需要修改hosts文件时,我们可以修改CoreDNS的configmap文件kubectl edit cm -n kube-sys…

BOSHIDA AC/DC电源模块:跟踪技术的创新之选

BOSHIDA AC/DC电源模块:跟踪技术的创新之选 AC/DC电源模块是一种能将交流电转化为直流电的设备,广泛应用于各种电子设备中。在过去的几十年中,AC/DC电源模块一直在不断发展和演进,以满足不断进步的科技需求。其中一项创新技术,即跟踪技术,成为AC/DC电源模块设计的首选。 …

Junit4遇上chatGPT

这是一篇适合Java工程师体质的AI开发教程。 本教程会教你写一个简单的junit4的Rule,该Rule在基于junit4的测试方法失败后,自动向GPT发送错误信息并通过GPT分析得出代码修改建议。 首先向AI问好 简单的通过AI,让它基于json格式生成相应的类文件,这样方便我们在代码中使用,而…