FastApi中的常见请求类型

FastApi中的常见请求类型

FastAPI

后端开发语言中,我钟情于node,高效的异步处理真是让我眼前一亮,同时,简单易懂的语法也让我非常倾心

但是但是,因为考虑要写一个深度学习算法的后端接口,所以不得不选用python作为后端进行开发,并不是我不喜欢Python,相反,Python作为我的第一语言,我同样非常喜欢,只不过我更喜欢用它来做数据分析

关于Python的后端框架,在Django和fastapi中,我最终选择了fastapi。相当长的一段时间里,我都是用Django在写后端,但是Django太臃肿了,重量级的框架很多地方难以学透,在现在前后端分离的大环境下,Django的模板语法优势也并不大

相反,fastapi只专注于后端接口开发,同时也提供了和node相似的异步处理程序。在学习fastapi过程中,记录了以下几种常见的接口请求方式:

一、主程序构建

在请求之前,先记录一下如何把后端服务跑起来

根目录下创建main.py文件,代码如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# author:HP
# datetime:2024/6/28 16:30

from fastapi import FastAPI
import uvicorn
from apps.app01 import app01

app = FastAPI()
app.include_router(app01)

if __name__ == '__main__':
    uvicorn.run("main:app", port=8001, reload=True)

两点需要注意:

  1. 路由分发,即app.include_router(app01),路由处理函数写在于main文件同目录下的apps文件夹下,该文件夹下面有一个app01.py的路由处理文件,里面就是各种路由的处理函数,当一个项目同时存在多个子项时,可以创建多个app.py文件,实现路由分发

  2. 服务启动命令uvicorn.run("main:app", port=8001, reload=True),很多情况下,需要在终端执行这句代码以启动服务,但这么操作非常不方便,也记不住,因此,把这行代码写在main函数中,只要运行这个程序,就可以正常启动服务了,注意,reload=True表示自动重启服务,也就是代码改了之后,服务就会自动重启

二、请求类型

请求类型大概包括路径参数、查询参数、请求体参数、form表单上传和文件上传这么几种,其中文件上传是最复杂的,我先把全部的代码放进来,然后一一解释

apps/app01.py中的代码:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# author:HP
# datetime:2024/6/28 16:30
from fastapi import APIRouter, Form, File, UploadFile
from pydantic import BaseModel
from datetime import date, datetime
from typing import List
import os

app01 = APIRouter()


class User(BaseModel):
    name: str = 'root'  # 默认值
    age: int
    birth: date
    friends: List[int]


# 路径参数
@app01.get('/user/{id}')
async def get_user(id: int):
    print(id)
    return {
        "user_id": id
    }


# 查询参数
@app01.get("/jobs")
async def get_jobs(kd, gj=None, xl=None):
    return {
        "kd": kd,
        "gj": gj,
        "xl": xl,
    }


# 请求体参数
@app01.post("/data")
async def get_data(data: User):
    return data


# form表单数据
@app01.post('/register')
async def register(username: str = Form(), password: str = Form()):
    print(username)
    print('----------')
    print(password)
    return {
        "username": username,
    }


# 上传单个文件
@app01.post('/upload')
async def upload(file: bytes = File()):
    # 这里的file直接就是字节流,没有其他信息
    # 将文件存储到服务器
    # 获取当前时间,精确到毫秒
    current_time = datetime.now().strftime('%Y%m%d%H%M%S%f')[:-3]  # 去掉最后的毫秒部分的最后一位,确保文件名合法
    filename = current_time + '.jpg'
    path = os.path.join('imgs', filename)
    with open(path, 'wb') as f:
        f.write(file)

    return {
        "status": 1,
        "message": "success",
        "file": filename,
    }


# 上传多个文件
@app01.post('/uploads')
async def uploads(files: List[bytes] = File()):
    for file in files:
        print(len(file))
    return {
        "file": len(files)
    }


# 更加常用的文件上传方式,但postman中无法测试,因为数据中不支持UploadFile类型的数据
# 上传单个文件
@app01.post('/uploadFlie')
async def upload_file(file: UploadFile):
    current_time = datetime.now().strftime('%Y%m%d%H%M%S%f')[:-3]  # 去掉最后的毫秒部分的最后一位,确保文件名合法
    filename = current_time + '.jpg'
    path = os.path.join('imgs', filename)
    with open(path, 'wb') as f:
        for line in file.file:
            f.write(line)
    return {
        "origin_name": file.filename,
        "sever_name": filename,
    }


# 上传多个文件
@app01.post('/uploadFiles')
async def upload_files(files: List[UploadFile]):
    print(files)
    return {
        "file": len(files),
    }

1、路径参数

# 路径参数
@app01.get('/user/{id}')
async def get_user(id: int):
    print(id)
    return {
        "user_id": id
    }

请求示例:

image-20240702102934385

请求参数写在路径上,通常用于处理表格中的数据,比较好理解

2、查询参数

# 查询参数
@app01.get("/jobs")
async def get_jobs(kd, gj=None, xl=None):
    return {
        "kd": kd,
        "gj": gj,
        "xl": xl,
    }

postman中的请求示例:

image-20240702103154842

这也挺简单的,以查询参数的形式传递参数,通常来说,就是路由中?后面的都是查询参数,用&分割

3、请求体参数

一般用是post请求中,把参数封装在body(请求体)中

# 请求体参数
@app01.post("/data")
async def get_data(data: User):
    return data

这里用到了pydantic中的BaseModel模型,User模型继承于BaseModel,主要得记住写法

同样看看postman中的请求示例:

image-20240702103648063

在postman中,body参数要写在raw下,这里不是表单数据,不能写在x-www-form-urlencoded中

其实也挺简单的

4、form表单参数

这里正好与第3点请求体参数比较一下

# form表单数据
@app01.post('/register')
async def register(username: str = Form(), password: str = Form()):
    print(username)
    print('----------')
    print(password)
    return {
        "username": username,
    }

fastapi中封装好了Form表单数据的数据类型,这和postman中的x-www-form-urlencoded定义的form数据是一样的

看看postman中的请求示例:

image-20240702104116745

参数位置不一样

5、文件上传

(1)上传单个文件
# 上传单个文件
@app01.post('/upload')
async def upload(file: bytes = File()):
    # 这里的file直接就是字节流,没有其他信息
    # 将文件存储到服务器
    # 获取当前时间,精确到毫秒
    current_time = datetime.now().strftime('%Y%m%d%H%M%S%f')[:-3]  # 去掉最后的毫秒部分的最后一位,确保文件名合法
    filename = current_time + '.jpg'
    path = os.path.join('imgs', filename)
    with open(path, 'wb') as f:
        f.write(file)

    return {
        "status": 1,
        "message": "success",
        "file": filename,
    }

目标,前端上传文件,并将文件保存在服务器中与main.py同名的imgs文件夹下,文件名是当前时间(到毫秒).jpg

注意,这里的file是字节流,可以直接写到文件中,同样,也可以在postman中测试

image-20240702104508468

服务器下的imgs文件夹下多了一张图片

image-20240702104558750

(2)上传多个文件
# 上传多个文件
@app01.post('/uploads')
async def uploads(files: List[bytes] = File()):
    for file in files:
        print(len(file))
    return {
        "file": len(files)
    }

这里没再写文件存储的过程,与上传单个文件差不多,看看postman中的示例:

image-20240702104810492

(3)UploadFile上传单个文件

前面两种情况应该已经能满足大部分情况了,但是,fastapi封装了一种专用于文件上传的UploadFile类,代码如下:

# 更加常用的文件上传方式,但postman中无法测试,因为数据中不支持UploadFile类型的数据
# 上传单个文件
@app01.post('/uploadFlie')
async def upload_file(file: UploadFile):
    current_time = datetime.now().strftime('%Y%m%d%H%M%S%f')[:-3]  # 去掉最后的毫秒部分的最后一位,确保文件名合法
    filename = current_time + '.jpg'
    path = os.path.join('imgs', filename)
    with open(path, 'wb') as f:
        for line in file.file:
            f.write(line)
    return {
        "origin_name": file.filename,
        "sever_name": filename,
    }

因为这是fastapi封装的,postman不兼容,所以postman没法测,用fastapi自带的接口测试文档看下示例:

image-20240702105207200

同样看看服务器端的imgs目录:

image-20240702105303058

可以看到,对应的地方多了一张图片

需要注意的是,这里上传的file,就并不再是纯字节流数据了,而是fastapi封装的UploadFile对象,需要知道这个对象里有哪些内容,可以查看源码,也可以借助编译器逐个去看

(4)UploadFile上传多个文件
# 上传多个文件
@app01.post('/uploadFiles')
async def upload_files(files: List[UploadFile]):
    print(files)
    return {
        "file": len(files),
    }

理解了UploadFile上传单个文件,多个文件就不难了,看看接口测试文档中的示例:

image-20240702105629868

无非是多了个添加item的选项而已

对象里有哪些内容,可以查看源码,也可以借助编译器逐个去看

好了,学习完接口的请求类型,后面应该要学习orm了。。

  • 26
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栀椩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值