技術筆記-專案架構,我目前的最佳實行 (python api server project)

更新 發佈閱讀 12 分鐘

開發生涯,不斷堆加著程式碼,總有那麼一天,只是不經意地修改,卻...突然壞掉了!然後,修很久都修不好。這說明了一件重要的事:專案結構脆弱;隨著認知程度和專案規模的變大,標準也跟著一直提升。而這就是系統要「轉骨」的時候了,為了長治久安,必須進行重構,才能迎接下一階段的成長。以下紀錄我目前的最佳實行。

source control 相關

根目錄的第一個東西,隱藏目錄 .git 和隱藏檔 .gitignore。這是為了 source control。

python 虛擬環境相關

第二個東西是隱藏目錄 .venv (個人習慣的命名),專為此專案的 python 執行環境,相關的操作指令如下:

# 以下指令在 zsh 終端機畫面,在專案根目錄執行,% 為提示符號
# 本專案指定使用 python3.11
% python3.11 -m venv ​.venv
% source .vnev/bin/activate

# 之後進入 python 虛擬環境,提示符號變為 (.venv)%
(.venv)% pip install --upgrade pip setuptools wheel
(.venv)% pip install -r requirements.txt

# requirements.txt 是另一個必須在根目錄的檔案,產生的指令如下:
(.venv)% pip freeze > requirements.txt

以上是專案最底層的資訊,非常重要,若有差錯,日後都是傷筋動骨的事,所有開發和執行的動作,都是基於此虛擬環境。

os 層級的檢查

比虛擬環境更底層的,是 os,在繼續發展之前,需要確認根基的穩固,相關指令如下:

# 看看目前的 python 版本,是什麼平台的​
(.vnev)% python -c "import platform; print(platform.machine())"
# 以我的環境為例,應該會輸出 arm64,如果是 x86,代表用到模擬的 x86 環境,
# 效率較差,必須重來。以下紀錄整個重來的過程。

# 很有可能,連用來安裝 python 的 brew 就已經是 x86 版本,那就會一路錯下去
# 重裝 arm 版本的 Homebrew,開一個乾淨的 terminal 執行以下指令
% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 檢查 brew 是哪一個 brew
% which brew
# 應該是 /opt/homebrew/bin/brew
# 也可以看看系統有多少 brew
% which -a brew
# 有可能多版本並存如下
# /opt/homebrew/bin/brew
# /usr/local/bin/brew​
# 這時就要看誰排在前面,若要確認先用 arm 版本的 brew,需改 ~/.zshrc
% nano ~/.zshrc
# 把這行加在最上面
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH"
# 執行一次 .zshrc,再檢查一次 which brew
% source ~/.zshrc​

# 用乾淨的 brew 安裝 pyenv
% brew install pyenv
# 用 pyenv 安裝 python
% pyenv install 3.11.14
% which python3.11
% python3.11 --version

需要以上嚴格的程序,確認正確的 python 版本。

cache 目錄

程式運行中,需要高頻率反覆存取的東西,而原始資料卻不會一直變動者,適合存成本地檔案。如「日 K 線」就是典型,昨天以前的資料,在當日之間是不會變動的,但計算波動與報酬,卻會經常用到,適合存起來快取。

wheel 目錄

有些套件,並沒有公開到外面的資料庫,如本系統使用的券商 api,是直接提供 .whl 檔,當佈署雲端時也是必須包含的。此外,也有可能再開 resource 目錄,反正只要 deploy 時要一併送上雲端的檔案,都可以開在專案根目錄,方便參用。

流程自動化所需 shell script file

如「佈署到雲端」的一系列動作,可以寫成 deploy.sh,放在專案根目錄。

#!/bin/bash
set -e # stop on error

echo "👉 Cleaning old package..."
rm -f myapp.zip

echo "👉 Packing all source files into myapp.zip..."
zip -r myapp.zip . \
-x ".venv/*" \
-x ".vscode/*" \
-x ".gitiqnore" \
-x "**/__pycache__/*" \
-x ".git/*" \
-x "candles_cache/*" \
-x "log/*" \
-x "**/log/*"

echo "👉 Adding cached price snapshots to the package..."
zip -r myapp.zip candles_cache/price_snapshot*
zip -r myapp.zip candles_cache/symbol_names*

echo "👉 Deploying to Azure App Service..."
az webapp deploy \
--resource-group aaabbb \
--name xxxyyy \
--src-path myapp.zip \
--type zip \
--restart true \
--clean true

echo "🎉 Deployment complete!"

原始碼

重點來了,因為專案根目錄已經太多資料了,我所有的原始碼都放在 src 目錄下面,且為了專案檔案間可以互相 import,最好是遵循正規的 package 規範。一個 package 就是一個目錄,為了有基準點,我把 src 也變成一個 package,所需動作就是在 src 目錄中新增一個檔案 __init __.py,檔案內容就先空著。

src 目錄中直接放置的程式碼很少,主要是作為入口的 main.py,和作為路由器的 router.py,其餘大量程式主要分為兩類,分別放置兩個目錄,controller and service,他們也都是 package,這樣 import 的規則就很簡單,全部採用「相對路徑」:

# main.py 引用同目錄的 newrouter.py:
from .newrouter import newrouter

# 在某個 service 目錄中,引用同一層的其他 service,也是同樣的方式:
from .firestoreService import FirestoreService

# controller 引用 service 的方式,從上兩層為參考點:
from ..newservice.fubonService import FubonService

package 的設置,大幅提升了專案的可攜性,在 deploy to cloud 時,降低踩雷機率。以前胡亂 import,可以跑就先撐著,苟延殘喘,某一天一定會爆,那時就被迫要做這件事了。

啟動 fastapi server 的方式

注意必須在虛擬環境提示符之下 (.venv)%,在專案根目錄,輸入:
uvicorn src.main:app --reload

重點就是,以「專案根目錄」為參考點,最清晰明瞭,不易出錯。以上 src 就是 package name,main 就是模組,app 就是 server instance,所以在 main.py 必須有一行:
app = FastAPI()

# main.py,這是程式進入點​
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from .newrouter import newrouter

app = FastAPI()

origins = [
"http://localhost:5173", # Vite local frontend
"http://127.0.0.1:5173",
"https://newman-portfolio.azurewebsites.net", # Azure frontend
]

app.add_middleware(
CORSMiddleware,
allow_origins=origins, # domains allowed, ["x"] for allow all
allow_credentials=True,
allow_methods=["*"], # GET, POST, etc.
allow_headers=["*"], # Authorization, Content-Type, ...
)

app.include_router(newrouter, prefix="/api")

部署到 azure app service

azure app service 中,重要且必要的設定如下:

  • Stack setting:選擇正確的 python 版本
  • Startup command:uvicorn src.main:app --host 0.0.0.0 --port 8000

在 deploy script 中會用到的重要識別資料:resource group name and name。

部署時最常用到的工具,就是 Log stream and SSH。

總結

以上紀錄的重點,基本上等同於「踩過的雷」,特此紀錄,以免再犯。

project/
├─ .venv/
├─ .git
├─ .gitignore
├─ cache/
├─ wheels/
├─ src/
│ ├─ __init__.py
│ ├─ main.py
│ ├─ newrouter.py
│ ├─ controller/
│ │ ├─ __init__.py
│ │ ├─ stockController.py
│ ├─ service/
│ │ ├─ __init__.py
│ │ ├─ fubonservice.py
├─ deploy.sh
├─ requirements.txt

Newman 2026/2/5

導覽頁:紐曼的技術筆記-索引

導覽頁:精明管家



留言
avatar-img
newman的沙龍
32會員
151內容數
漫步是一種境界。
newman的沙龍的其他內容
2025/11/19
沒錯,我又重來了。近期又重新享受了一波,沈浸在程式開發的快樂。好像已過 20 年想做的事,又重新濃縮式的跑了一遍,速度是幾十倍速的飛快。 啓後必有承先 因著對資訊技術的愛好,五年來我得到充分的自由,可以天馬行空的嘗試探索。雖然沒有企業或團隊資源的支持,但可玩的東西已經很多了。 記得那個自由的起
Thumbnail
2025/11/19
沒錯,我又重來了。近期又重新享受了一波,沈浸在程式開發的快樂。好像已過 20 年想做的事,又重新濃縮式的跑了一遍,速度是幾十倍速的飛快。 啓後必有承先 因著對資訊技術的愛好,五年來我得到充分的自由,可以天馬行空的嘗試探索。雖然沒有企業或團隊資源的支持,但可玩的東西已經很多了。 記得那個自由的起
Thumbnail
2025/10/21
分散之必須 「分散」是消除風險的重要方法。當我們把資金分散到多個標的,並不能真正安心,因為許多標的存在著相關性。比如說同產業的多標的,容易同漲同跌,導致雖然標的分散了,實際上風險卻沒有分散。分散的方法可以基於基本面的知識,也可以基於量化分析,而最好是兩者相輔相成。比如說最近華邦電與力積電一同飆漲,
Thumbnail
2025/10/21
分散之必須 「分散」是消除風險的重要方法。當我們把資金分散到多個標的,並不能真正安心,因為許多標的存在著相關性。比如說同產業的多標的,容易同漲同跌,導致雖然標的分散了,實際上風險卻沒有分散。分散的方法可以基於基本面的知識,也可以基於量化分析,而最好是兩者相輔相成。比如說最近華邦電與力積電一同飆漲,
Thumbnail
2025/09/16
又來搞認證了,久久搞一次,每次都卡關,記得上一次做 web 前端也弄很久,有留下記錄,是有點久的舊文: 技術-前端類-angular 網頁整合 google login (2022/4/20) 認證,或指廣泛的關於安全性的議題,超級重要的,但在小咖咖階段就還好,沒有人會想來攻擊我,沒有肉啊。但當
Thumbnail
2025/09/16
又來搞認證了,久久搞一次,每次都卡關,記得上一次做 web 前端也弄很久,有留下記錄,是有點久的舊文: 技術-前端類-angular 網頁整合 google login (2022/4/20) 認證,或指廣泛的關於安全性的議題,超級重要的,但在小咖咖階段就還好,沒有人會想來攻擊我,沒有肉啊。但當
Thumbnail
看更多
你可能也想看
Thumbnail
這篇文章將教你如何在 FastAPI 中宣告並讀取路徑參數 (Path Parameters),你將學會如何透過 URL 傳遞變數給伺服器,實現取得特定用戶資料或商品資訊等功能。
Thumbnail
這篇文章將教你如何在 FastAPI 中宣告並讀取路徑參數 (Path Parameters),你將學會如何透過 URL 傳遞變數給伺服器,實現取得特定用戶資料或商品資訊等功能。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
在 FastAPI 的依賴注入中,yield 主要用於建立「帶有清理功能的依賴項」。簡單來說,使用 return 的依賴項只負責「創建」資源,而使用 yield 的依賴項則能同時處理「準備資源」與「清理資源」。
Thumbnail
在 FastAPI 的依賴注入中,yield 主要用於建立「帶有清理功能的依賴項」。簡單來說,使用 return 的依賴項只負責「創建」資源,而使用 yield 的依賴項則能同時處理「準備資源」與「清理資源」。
Thumbnail
FastAPI 是什麼?為什麼選它? 這是一個用 Python 寫的超輕量 Web API 框架,速度快、語法直觀。 適合拿來把你的模型包裝成 API,如你訓練好一個分類模型,用 FastAPI 做成 /predict 介面,就能讓別人輸入資料馬上得到結果。 對 AI 團隊來說:開發快、上線
Thumbnail
FastAPI 是什麼?為什麼選它? 這是一個用 Python 寫的超輕量 Web API 框架,速度快、語法直觀。 適合拿來把你的模型包裝成 API,如你訓練好一個分類模型,用 FastAPI 做成 /predict 介面,就能讓別人輸入資料馬上得到結果。 對 AI 團隊來說:開發快、上線
Thumbnail
這篇文章將教你如何在電腦上建置 Python 的 Web 框架:FastAPI,你將學會建立隔離的開發環境、安裝必要套件,並寫出你的第一支 API 程式。
Thumbnail
這篇文章將教你如何在電腦上建置 Python 的 Web 框架:FastAPI,你將學會建立隔離的開發環境、安裝必要套件,並寫出你的第一支 API 程式。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
在 FastAPI 開發中,ORM 模型是用來與資料庫進行互動的橋樑。簡單來說,它將Python 的類別 (Class)對應到資料庫的表格 (Table),並將類別的屬性對應到表格的欄位 (Column)。
Thumbnail
在 FastAPI 開發中,ORM 模型是用來與資料庫進行互動的橋樑。簡單來說,它將Python 的類別 (Class)對應到資料庫的表格 (Table),並將類別的屬性對應到表格的欄位 (Column)。
Thumbnail
這篇文章將教你如何使用 FastAPI 的 Query 與 Path 函式,對 API 的輸入參數進行嚴格的格式驗證,並且為 API 文件添加描述資訊。
Thumbnail
這篇文章將教你如何使用 FastAPI 的 Query 與 Path 函式,對 API 的輸入參數進行嚴格的格式驗證,並且為 API 文件添加描述資訊。
Thumbnail
這篇文章將教你如何在 FastAPI 中宣告與使用查詢參數 (Query Parameters),讓你能實現資料過濾、搜尋與分頁等功能。
Thumbnail
這篇文章將教你如何在 FastAPI 中宣告與使用查詢參數 (Query Parameters),讓你能實現資料過濾、搜尋與分頁等功能。
Thumbnail
這篇文章將教你如何使用 FastAPI 的「依賴注入 (Dependency Injection)」,學會依賴注入後,你不再需要重複複製貼上相同的檢查邏輯,或是手動建立資料庫連線。
Thumbnail
這篇文章將教你如何使用 FastAPI 的「依賴注入 (Dependency Injection)」,學會依賴注入後,你不再需要重複複製貼上相同的檢查邏輯,或是手動建立資料庫連線。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News