Try   HackMD

FastAPI APIRoute() 應用實作 - Route in Large System

tags: backend

Copyright 2021, 月下麒麟


Target

查爾斯成立的公司已邁入第10年,隨著公司組織的擴張
不得不想個辦法,為賺錢部門裁切出去成為一個獨立的公司
否則,這營運、經營起來的難度,已超出查爾斯當年的預期
這令他白髮掉滿地

今天會說明關於URL與Route的應用
(咦 Route是什麼!?)

Concept

舉個實例顏氏牧場來說 (單純覺得它網頁做得很漂亮 作為引用,沒有業配也沒有工商XD)

牧場主頁,裡面依序有五個分頁(理念、食宿、預約、風情、前往)

https://yenpasture.com/pasture1



牧場理念

https://yenpasture.com/pasture1/about.php



露營食宿

https://yenpasture.com/pasture1/camp.php



其他分頁以此類推,就不繼續列舉
是否有發現一個規律呢

觀察1
我再把這幾個URL放在一起 觀察看看

https://yenpasture.com/pasture1
https://yenpasture.com/pasture1/about.php
https://yenpasture.com/pasture1/camp.php
https://yenpasture.com/pasture1/scene.php
https://yenpasture.com/pasture1/map.php

在主結構pasture1下,有四個分頁,依序為about, camp, scene, map
對應到UI的畫面,當然使用者就能一目了然這幾個分頁的功能

再對應到後端的開發、管理,做好切分分類的工作後,未來無論是修改或是擴增,絕對都會很方便操作。

觀察2
如果你具備強烈的好奇心,你可能會跟我一樣想有pasture1,那是不是也會有pasture2呢
沒錯,筆者當時也是這樣思考的

https://www.yenpasture.com/pasture2  #這個會出現404 not found
https://www.yenpasture.com/pasture2/ #這個會redirect Website Expired

但遺憾的是開發者並沒有這樣想 可惡 猜錯了
不過,這樣觀察會發現,它網頁原本應該還是架在pasture2的XD

觀察3
推測它的2應該有變更過啦XD
或許跟他的中文命名有相關,但是1也沒有再回頭重新修改了(茶~)

https://www.yenpasture2.com/workshop # 牧場2在這裡

|--yenpasture/ |--yenpasture/pasture1/ | |--yenpasture/pasture1/about.php | |--yenpasture/pasture1/camp.php | |--yenpasture/pasture1/booking.php | |--yenpasture/pasture1/scene.php | |--yenpasture/pasture1/map.php | |--yenpasture2/pasture/ | |--yenpasture2/pasture/events | |--yenpasture2/pasture/shop | |--yenpasture2/pasture/photography | |--yenpasture2/pasture/picnic | |--yenpasture2/pasture/party | |--yenpasture2/pasture/2021-marketing | |--yenpasture2/pasture/about

URL就不多加解釋啦
至於Route在中文上會稱作路由,可以把它理解成一種URL切換的過程(路徑)
Route是後端再切分邏輯做使用的
白話來說,當你網頁畫面點擊顏氏牧場1的關於
故後端需要把yenpasture/pasture1/about這段URL,
切換到這個位置(顏氏牧場1的關於)


Implement

廢話不多說,讓我們進行實作吧!

Directory Achitecture

|--app |--__init__.py |--main.py | |--\route1 | |--__init__.py | |--router1.py | |--\route2 |--__init__.py |--router2.py

URLs Achitecture

當然,你也可以把結構寫成這個樣子

|--127.0.0.1:8001/ |--127.0.0.1:8001/router |--127.0.0.1:8001/router/1 |--127.0.0.1:8001/router/2

底下的架構,主要是想讓router1跟router2是平行關係的
至於上例好,還是下例好,就不在本次的討論範圍
主要要展示如何使用FastAPI的 APIRouter的功能

|--127.0.0.1:8001/ |--127.0.0.1:8001/router1 |--127.0.0.1:8001/router2

另一精神是為了解決資料夾分層結構的問題
當撰寫的系統日趨龐大,勢必就會遇到程式分類的問題
那為了避免Python在import來 import去的,導致產生import loop與route錯誤的問題
故就來使用這方便的工具吧

Code-router1

# router1.py from fastapi import FastAPI, APIRouter, HTTPException router = APIRouter() # point! @router.get("/router1") def router1() -> dict: return {"msg":"Hello Router1"}

Code-router2

# router2.py from fastapi import FastAPI, APIRouter, HTTPException router = APIRouter() # point! @router.get("/router2") def router1() -> dict: return {"msg":"Hello Router2"}

Code-main

from fastapi import FastAPI, APIRouter, HTTPException # 將route1、2資料夾內的router1、2 python檔引入 from route1 import router1 from route2 import router2 app = FastAPI() # 以app作為FastAPI實例 api_router = APIRouter() # 以api_router作為APIRouter實例,本次重點! api_router.include_router(router1.router) # 把router1檔案裡的路由結合進api_router api_router.include_router(router2.router) # 把router2檔案裡的路由結合進api_router @api_router.get("/") def root() -> dict: """ Root Get """ return {"msg":"Hello root"} app.include_router(api_router) # app實例將api_router的路由結合進去 if __name__ == "__main__": import uvicorn uvicorn.run(app, host="127.0.0.1", port=8001)

執行後,成果如下









Reference

FastAPI Bigger Applications - Multiple Files¶

Supplement

1
這個功能就類似於flask的Blueprints

If you come from Flask, this would be the equivalent of Flask's Blueprints.

2
你可能會擔心切換路由,會產生網路效能的問題,進而造成delay

You don't have to worry about performance when including routers.
This will take microseconds and will only happen at startup.
So it won't affect performance. ⚡

Summary

滿強大的一個功能,使用起來也很方便操作
希望有幫助到你的學習