You are currently viewing قرار دادن کلاینت TypeScript خود در یک Backend پایتون |  توسط Itai Bitan

قرار دادن کلاینت TypeScript خود در یک Backend پایتون | توسط Itai Bitan


عکس از Markus Spiske در Unsplash

راهنمای عملی کامل

برنامه React خود را با وب سرور FastAPI ترکیب کنید

در این راهنما، یاد خواهید گرفت که چگونه یک برنامه ساده TypeScript React را در یک بسته بندی کنید بسته پایتون و آن را از سرور وب FastAPI Python خود سرو کنید. اگر می خواهید کد کامل را ببینید، مخازن مشتری و سرور را بررسی کنید. بیا شروع کنیم!

در طول فرآیند توسعه، شما احتمالا از دو IDE مختلف استفاده می کنید:

  1. یک پنجره TypeScript یا JavaScript React App که بر روی یک پورت گوش دادن اختصاصی (مثلاً 5173) اجرا می شود تا به صفحات کلاینت/فرانت پایانی ارائه شود.
  2. Python FastAPI در حال اجرا بر روی یک پورت دیگر (مثلا 8080) برای سرویس REST API.

به عبارت دیگر، شما دو سرور مختلف دارید که به صورت محلی اجرا می شوند. هر بار که می خواهید با سرور FastAPI خود تماس بگیرید، مرورگر با دو سرور مختلف تعامل دارد.

توسعه محلی (تصویر توسط نویسنده)

در حالی که به صورت محلی خوب کار می کند (ج localhost)، هنگام استقرار این کد با خطای “Cross-Origin Request Blocked” در مرورگر خود مواجه خواهید شد. قبل از اینکه کد خود را به تولید برسانید، بهترین کار این است که هم صفحات سرویس گیرنده و هم REST API را از یک سرور وب پشتیبان ارائه دهید. به این ترتیب مرورگر با یک Backend تعامل خواهد داشت. برای امنیت، عملکرد و سادگی بهتر است.

آماده سازی برای تولید (تصویر توسط نویسنده)

1. یک برنامه Simple React ایجاد کنید

اول، در مال شما workspace دایرکتوری، بیایید یک برنامه TypeScript React جدید با استفاده از vite ایجاد کنیم:

~/workspace ➜ npm create vite@latest
✔ Project name: … vite-project
✔ Select a framework: › React
✔ Select a variant: › TypeScript

سپس وارد دایرکتوری پروژه جدید شوید، وابستگی ها را نصب کنید و برنامه را اجرا کنید (http://localhost:5173):

~/workspace ➜ cd vite-project
~/workspace/vite-project ➜ npm install
~/workspace/vite-project ➜ npm run dev

شما باید چیزی شبیه به:

اولین الگوی Vite React (تصویر توسط نویسنده)

اکنون بیایید یک افزودنی کوچک به الگو ایجاد کنیم – یک تماس HTTP ناهمزمان به باطن FastAPI آینده اضافه می کنیم تا وضعیت آن را دریافت کنیم:

function App() {
...
const [health, setHealth] = useState('');

useEffect(() => {
const getStatus = async () => {
const response = await fetch('/v1/health-check/liveness', {
method: 'GET',
});
let status: { [status: string]: string } = {};
try {
status = await response.json();
} catch (err) {
console.log(`failed to get backend status. ${err}`);
}
setHealth(status['status'] || 'unknown');
};
getStatus();
}, []);

return (
...
<div>Backend Status: {health}</div>
...
)
}

و اکنون باید چیزی شبیه به این دریافت کنیم:

با تماس پشتیبان (تصویر توسط نویسنده)

در این لحظه، وضعیت Backend است unknown چون هنوز آن را اجرا نکرده ایم. نگران نباش به زودی بهش میرسیم در نهایت، اجازه دهید مشتری را برای بسته بندی بعدا بسازیم:

~/workspace/vite-project ➜ npm run build

خروجی کامپایل باید a ایجاد کند dist پوشه ای با کد بهینه سازی نهایی که به شکل زیر است:

└── dist/
├── assets/
├── static/
└── index.html

2. ساخت بسته پایتون

در این مرحله به پایتون سوئیچ می کنیم. ترجیح می دهم در محیط مجازی برای انزوا کار کنم. ما در یک محیط مجازی اختصاصی نصب خواهیم کرد twine و build برای ایجاد بسته پایتون:

~/workspace/vite-project ➜ python3 -m venv venv
~/workspace/vite-project ➜ . venv/bin/activate
~/workspace/vite-project (venv) ➜ python -m pip install --upgrade pip
~/workspace/vite-project (venv) ➜ pip install twine==5.0.0 build==1.2.1

بیایید یک مورد جدید ایجاد کنیم setup.py فایل در پوشه ریشه (vite-project، با محتوای زیر:

from setuptools import setup
from pathlib import Path

cwd = Path(__file__).parent
long_description = (cwd / "README.md").read_text()

setup(
name="vite-project",
version="0.0.1",
package_dir={"vite_project": "dist"},
package_data={"vite_project": ["**/*.*"]},
long_description=long_description,
long_description_content_type="text/markdown",
)

و برای ایجاد پکیج موارد زیر را اجرا کنید:

~/workspace/vite-project (venv) ➜ python setup.py sdist -d tmp
~/workspace/vite-project (venv) ➜ python -m build --wheel --outdir tmp
~/workspace/vite-project (venv) ➜ twine upload -u ${USERNAME} -p ${PASSWORD} --repository-url ${REPO_URL} tmp/*

اگر قصد دارید بسته خود را در یک مخزن راه دور مانند PyPI، JFrog Artifactory و غیره آپلود کنید، خط آخر بالا اختیاری است.

3. یک وب سرور FastAPI Python ایجاد کنید

مرحله آخر ساخت سرور پایتون و استفاده از بسته مشتری است. برای این منظور ما:

  • یک مورد جدید ایجاد کنید backendاشاره گر
  • یک محیط مجازی جدید ایجاد کنید.
  • بسته های مربوطه و بسته مشتری ما را نصب کنید:
~/workspace/backend ➜ python3 -m venv venv
~/workspace/backend ➜ . venv/bin/activate
~/workspace/backend (venv) ➜ python -m pip install --upgrade pip
~/workspace/backend (venv) ➜ pip install fastapi==0.110.0 uvicorn==0.29.0
~/workspace/backend (venv) ➜ pip install ~/workspace/vite-project/tmp/vite-project-0.0.1.tar.gz

توجه داشته باشید که بسته مشتری خود را از مسیر محلی که قبلا ایجاد کرده بودیم نصب کردیم. اگر بسته خود را در یک مخزن راه دور آپلود کرده اید، می توانید آن را با استفاده از:

~/workspace/backend (venv) ➜ pip install --extra-index-url https://${USERNAME}:${PASSWORD}@${REPO_URL} vite-project==0.0.1

بعد، بیایید یک سرور ساده پایتون (2 فایل) ایجاد کنیم:

__main__.py

from distutils.sysconfig import get_python_lib
from fastapi import FastAPI
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from backend.health_router import router
from uvicorn import run

def create_app():
app = FastAPI(
title="Backend Server",
)
app.include_router(router)

client_path = f"{get_python_lib()}/vite_project"
app.mount("/assets", StaticFiles(directory=f"{client_path}/assets"), name="assets")
app.mount("/static", StaticFiles(directory=f"{client_path}/static"), name="static")

@app.get("/{catchall:path}")
async def serve_react_app(catchall: str):
return FileResponse(f"{client_path}/index.html")

return app

def main():
app = create_app()
run(app, host="0.0.0.0", port=8080)

if __name__ == "__main__":
main()

health_router.py

from typing import Literal
from typing_extensions import TypedDict
from fastapi import APIRouter, status

STATUS = Literal["success", "error", "partial", "unknown"]

class ReturnHealthcheckStruct(TypedDict):
status: STATUS

router = APIRouter(
prefix="/v1/health-check",
tags=["Health Check"],
)

@router.get(
"/liveness",
summary="Perform a Liveness Health Check",
response_description="Return HTTP Status Code 200 (OK)",
status_code=status.HTTP_200_OK,
response_model=ReturnHealthcheckStruct,
)
async def liveness() -> ReturnHealthcheckStruct:
return {"status": "success"}

در پیاده‌سازی بالا، با نصب کردن، پشتیبانی را برای ارائه هر فایل استاتیک از برنامه مشتری خود اضافه کردیم static و assets پوشه ها و همچنین هر فایل مشتری دیگری که توسط سرور پایتون ما ارائه می شود.

ما همچنین یک نقطه پایانی ساده GET ایجاد کردیم، v1/health-check/liveness که ساده برمیگرده {“status": “success"} پاسخ JSON به این ترتیب می‌توانیم اطمینان حاصل کنیم که سرور ما هم فایل‌های مشتری ثابت و هم API RESTful سمت سرور را مدیریت می‌کند.

حالا اگر به localhost:8080 برویم، می‌توانیم مشتری خود را در حال اجرا ببینیم. توجه کن به وضعیت Backend در زیر، در حال حاضر آن است success (نسبت به. تا unknown).

اجرای یک سرور پایتون در کنار یک برنامه React (تصویر توسط نویسنده)

در این آموزش، ما یک برنامه ساده React ایجاد کردیم که یک تماس واحد را با backend برقرار می کند. ما این برنامه مشتری را به عنوان یک بسته Python بسته بندی کردیم و آن را از وب سرور Python FastAPI خود ارائه کردیم.

استفاده از این رویکرد به شما امکان می‌دهد از بهترین‌های هر دو جهان استفاده کنید: TypeScript و React برای فرانت‌اند و Python با FastAPI برای Backend. با این حال، ما می خواهیم انسجام بالا و اتصال آزاد بین این دو جزء را حفظ کنیم. به این ترتیب شما از تمام مزایای زیر برخوردار خواهید شد:

  • سرعت، با تقسیم قسمت جلویی و انتهایی به مخازن مختلف، هر قسمت می تواند توسط تیم متفاوتی توسعه یابد.
  • پایداری و کیفیت، با قفل کردن بسته کلاینت نسخه شده و ضربه زدن به آن تنها زمانی که سرور آماده پشتیبانی از نسخه مشتری جدید است.
  • امنیت – مرورگر تنها با یک سرور پشتیبان تعامل دارد. ما نیازی به فعال کردن CORS یا سایر راه‌حل‌های مخل امنیت نداریم.
  • سادگی – با کار از طریق یک سرور واحد



Source link