Python|FastAPI的路由介绍及使用

本文将介绍如何使用 Router 路由处理 FastAPI 中的请求。同时以我自己开发系统的后端为例进行FastAPI使用的说明。

什么是路由

路由 Router 就像是一个流水线上的线长,协调生产,下达命令给不同的组长进行分工,然后执行基本的任务。路由器的工作目的是,在团队中工作时,您可能必须在团队成员(这里的团队负责人是队长)之间分配复杂性,这将有助于更快地完成项目,正确的 SME 将在该分支/路由器上工作.

img

路由是构建网络应用的一个重要部分。FastAPI 中的路由是灵活和方便的。路由是处理从客户端发送到服务器的 HTTP 请求的过程。HTTP 请求被发送到定义的路由,这些路由有定义的处理程序来处理请求和响应。这些处理程序被称为 Route Handler。

FastAPI 中的路由

参考 FastAPI 文档对路由器的介绍:如果你正在构建一个应用程序或一个 Web API,你很少会把所有东西都放在一个文件中。 FastAPI 提供了一个方便的工具来构建您的应用程序,同时保持所有的灵活性。

先来看一个例子:

from fastapi import FastAPI
app = FastAPI()

# 设置一个首页
@app.get('/')
async def welcome() -> dict:
	return {"message": "Welcome to my Page"}

uvicorn 工具指向 FastAPI 的实例,为应用程序服务:

uvicorn main:app --port 8000 --reload
image-20230604215810816

访问

INFO:     Will watch for changes in these directories: ['D:\\WH_Flower\\backend']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [23056] using StatReload
INFO:     Started server process [10788]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

FastAPI()实例可用于路由操作,正如前面所见。然而,这种方法通常用于在路由过程中只能处理单一路径的应用程序。在使用 FastAPI() 实例创建一个执行独特功能的单独路由的情况下,应用程序将无法运行两个路由,因为 uvicorn 工具只能运行一个入口点。

如果有多个路由

让我们了解一下如何用代码来创建路由器,下面是我们的基本(非路由器)代码,在这里,我创建了一个例子:主页、添加和删除用户的页面。由于这是一个例子,我只取了两个父路径为 '/user/' 的函数,但在现实生活中,你可能会发现 20-30 个这样的函数,所以需要创建路由器,因为在一个文件中处理太多复杂的东西会变得很麻烦。

from fastapi import FastAPI

app = FastAPI()

@app.get('/') 
async def welcome() -> dict:
    return { "message": "Welcome to my Page"}

@app.get('/user/create_user')
def add_numbers():
    return { "message": "Add a user!"}

@app.get('/user/delete_user')
def add_strings():
    return { "message": "Delete a user!"}

那么,问题来了,我们如何处理需要一系列路由执行不同功能的广泛应用程序呢?答案是 APIRouter 类。

利用 APIRouter 类实现路由

APIRouter 类属于 FastAPI 包,为多个路由创建路径操作。APIRouter 类鼓励应用程序路由和逻辑的模块化和组织化。

APIRouter 类从 fastapi 包中导入,并创建一个实例。路由方法被创建并从创建的实例中分发,我这里以用户的基本功能为例,如下:

from fastapi import APIRouter

# create router
router = APIRouter(
    prefix='/user',
    tags = ['用户相关']
)

上面的代码将创建一个路由器实例,它可以带有一些参数,比如下面两个的含义:

  • prefix:在特定页面中 fastapi 提供的每个装饰器中添加前缀
  • tags:这将帮助我们找到属于哪个类别的功能,同时这会显示在FastAPI自动生成的文档中(类似于相关文章的主题标签)

注意,后方初学者可能会觉得难度飙升,但是没关系,我们这里只关心路由的情况,具体的API的内容不用管。

然后可以利用 APIRouter 类创建一个新的路径操作,创建一个新的python包apis,然后在这个包里新建一个文件夹v1,代表我们各类API的版本号(这里建不建都是可以的,看你个人),这里展示一下用户相关的API:

# -*- coding: utf-8 -*-
"""
PROJECT_NAME: backend 
FILE_NAME: user 
AUTHOR: welt 
E_MAIL: tjlwelt@foxmail.com
DATE: 2023/5/11 
"""
from typing import List
from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.orm import Session

from curd import user_curd
from schemas import user_schema
from utils.db_connect import get_db

userRouter = APIRouter(tags=['用户相关'])


@userRouter.post("/register/", response_model=user_schema.User, summary="用户注册")
def create_user(user: user_schema.UserCreate, db: Session = Depends(get_db)):
	"""
	创建用户
	"""
	db_user = user_curd.get_user_by_email(db, email=user.email)
	if db_user:
		raise HTTPException(status_code=400, detail="Email already registered")
	return user_curd.create_user(db=db, user=user)


@userRouter.get("/users/", response_model=List[user_schema.User], summary="获取全部的用户列表")
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
	"""
	获取全部用户
	"""
	users = user_curd.get_users(db, skip=skip, limit=limit)
	return users


@userRouter.get("/users/{user_id}", response_model=user_schema.User, summary="根据用户ID来获取用户")
def read_user(user_id: int, db: Session = Depends(get_db)):
	"""
	详情页用到
	"""
	db_user = user_curd.get_user(db, user_id=user_id)
	if db_user is None:
		raise HTTPException(status_code=404, detail="User not found!")
	return db_user


@userRouter.post("/users/{user_id}", summary="根据用户ID删除用户")
def delete_user(user_id: int, db: Session = Depends(get_db)):
	"""
	根据用户ID删除用户(表格中管理用户时使用)
	"""
	return user_curd.delete_user(db=db, user_id=user_id)


@userRouter.post("/update_user_info/{user_id}", summary="更新用户信息")
async def update_user(user_id: int, user: user_schema.UserCreate, db: Session = Depends(get_db)):
	"""
	更新用户信息页面API
	"""
	db_user = user_curd.get_user_by_email(db, email=user.email)
	if db_user:
		if db_user.id == user_id:
			return user_curd.update_user(db=db, user_id=user_id, user=user)
		else:
			raise HTTPException(status_code=400, detail="Email already registered!")
	return user_curd.update_user(db=db, user_id=user_id, user=user)


@userRouter.post("/update_user_avatar/", summary="更新用户头像")
async def update_user(user: user_schema.UserChangeAvatar, db: Session = Depends(get_db)):
	"""
	更新用户信息页面API
	"""
	return user_curd.update_user_avatar(db=db, user=user)


@userRouter.get("/login/", summary="用户登录")
async def user_login(email: str, password: str, db: Session = Depends(get_db)):
	"""
	用户登录API
	"""
	db_user = user_curd.get_user_by_email(db, email)
	hash_password = password + 'notreallyhashed'
	if db_user is None:
		raise HTTPException(status_code=404, detail="User not found!")
	if hash_password == db_user.hashed_password:
		return db_user
	else:
		return {"code": 501, "message": "密码错误!"}


@userRouter.post("/delete_user/{user_id}", summary="删除用户")
async def delete_point(user_id: int, db: Session = Depends(get_db)):
	"""
	删除用户
	"""
	return user_curd.delete_user(db=db, user_id=user_id)

因为我还需要地图点相关和详情页相关的API,评论摆烂了不想做,所以最终的文件目录结构如下:

image-20230604220545960

将APIRouter 添加到FastAPI实例

APIRouter 类的工作方式与 FastAPI 类的工作方式相同。然而, uvicorn 不能使用 APIRouter 实例为应用程序服务,这与FastAPI 不同。使用 APIRouter 类定义的路由需要被添加到 FastAPI 实例中,以实现它们的功能。

为了使刚刚定义的路由可见,我们将使用 include_router() 方法把 add_router 路径操作处理程序到主 FastAPI 实例中,如下:

from fastapi import FastAPI

app = FastAPI()

# 设置一个首页
@app.get('/')
async def welcome() -> dict:
	return {"message": "Welcome to my Page"}

# 添加FastAPI的API路由
app.include_router(User.userRouter)
app.include_router(MapPoints.pointRouter)
app.include_router(Abstract.abstractRouter)

include_router(router, ...) 方法负责在主程序的实例中加入用 APIRouter 类定义的路由添加到主应用程序的实例中,以使路由变得可见。

测试 Router 功能

启动 uvicorn 服务:

uvicorn src.main:app --reload --port 8000

在控制台看到如下信息,表示服务启动成功:

INFO:     Will watch for changes in these directories: ['D:\\WH_Flower\\backend']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [23056] using StatReload
INFO:     Started server process [10788]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

浏览器如下,访问 http://127.0.0.1:8000/

image-20230604222310300

最后,通过访问 http://127.0.0.1:8888/docs 来查看我们刚刚定义的接口,我们将看到自动 API 文档,包括来自所有子模块的路径,使用正确的路径(和前缀)和正确的标签名:

image-20230604222443696

点击try it out!可以测试你的API,当然这里我是已经写了相关内容的:

image-20230604222709107
posted @ 2023-06-04 22:34  Weltㅤ  阅读(2067)  评论(0编辑  收藏  举报