Creazione del pacchetto del client TypeScript in un backend Python |  di Itay Bittan |  Aprile 2024

 | Intelligenza-Artificiale

fotografato da Markus Spike SU Unsplash

UNA GUIDA PRATICA COMPLETA

Combina la tua applicazione React con il server web FastAPI

In questa guida imparerai come creare un pacchetto di un semplice TypeScript Reagire all'applicazione in un Pacchetto Python e servilo dal tuo API veloce Server web Python. Dai un'occhiata a cliente e il server repository, se vuoi vedere il codice completo. Iniziamo!

Durante il processo di sviluppo, probabilmente utilizzi due IDE diversi:

  1. Finestra TypeScript o JavaScript React App, in esecuzione su una porta di ascolto dedicata (ad esempio, 5173) per servire le pagine client/frontend.
  2. Python FastAPI, in esecuzione su una porta diversa (ad esempio, 8080) per servire un'API REST.

In altre parole, hai due server diversi in esecuzione localmente. Ogni volta che desideri chiamare il tuo server FastAPI, il browser interagisce con due server diversi.

Sviluppo locale (Immagine dell'autore)

Anche se funziona bene localmente (in localhost), riscontrerai un errore “Richiesta multiorigine bloccata” nel tuo browser quando distribuisci quel codice. Prima di portare il codice in produzione, la procedura migliore è quella di servire sia le pagine client che l'API REST dallo stesso server Web backend. In questo modo il browser interagirà con un singolo backend. È migliore per sicurezza, prestazioni e semplicità.

Preparazione per la produzione (immagine dell'autore)

1. Crea un'applicazione Simple React

Innanzitutto, nel tuo workspace directory, creiamo una nuova applicazione TypeScript React utilizzando velocemente:

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

Quindi, accedi alla nuova directory del progetto, installa le dipendenze ed esegui l'applicazione (http://localhost:5173):

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

Dovresti vedere qualcosa come:

Modello First Vite React (immagine dell'autore)

Ora facciamo una piccola aggiunta al modello: aggiungeremo una chiamata HTTP asincrona al futuro backend FastAPI per ottenere il suo stato:

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>
...
)
}

E ora dovremmo ottenere qualcosa del genere:

Con una chiamata al Backend (Immagine dell'Autore)

A questo punto, il Stato del back-end È unknown perché non l'abbiamo ancora implementato. Non preoccuparti, ce ne occuperemo a breve. Infine, creiamo il client per impacchettarlo in seguito:

~/workspace/vite-project ➜ npm run build

L'output di compilazione dovrebbe creare un file dist cartella con il codice ottimizzato finale simile a questo:

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

2. Costruire un pacchetto Python

A questo punto passiamo a Python. Preferisco lavorare in a ambiente virtuale per l'isolamento. In un ambiente virtuale dedicato, installeremo twine E build per creare il nostro pacchetto Python:

~/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

Creiamone uno nuovo setup.py file nella cartella principale (vite-project), con il seguente contenuto:

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",
)

ed esegui quanto segue per creare il pacchetto:

~/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/*

L'ultima riga sopra è facoltativa se intendi caricare il tuo pacchetto su un repository remoto come PyPI, JFrog Artifabbricaeccetera.

3. Creare un server Web Python FastAPI

Il passaggio finale consiste nel creare il server Python e utilizzare il pacchetto client. Per questo:

  • Creane uno nuovo backenddirectory.
  • Creare un nuovo ambiente virtuale.
  • Installa i pacchetti pertinenti e il nostro pacchetto client:
~/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

Tieni presente che abbiamo installato il nostro pacchetto client da un percorso locale creato in precedenza. Se hai caricato il tuo pacchetto su un repository remoto, puoi installarlo con:

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

Successivamente, creiamo un semplice server Python (2 file):

__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()

salute_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"}

Nell'implementazione di cui sopra, abbiamo aggiunto il supporto per servire qualsiasi file statico dalla nostra applicazione client montando il file static E assets cartelle, così come qualsiasi altro file client che sarà servito dal nostro server Python.

Abbiamo anche creato un semplice endpoint GET, v1/health-check/liveness che restituisce un semplice {“status": “success"} Risposta JSON. In questo modo possiamo garantire che il nostro server gestisca sia i file statici del client che la nostra API RESTful lato server.

Ora, se andiamo a host locale:8080 possiamo vedere il nostro client attivo e funzionante. Presta attenzione a Stato del back-end sotto, è adesso success (piuttosto che unknown).

Esecuzione di un server Python insieme all'applicazione React (immagine dell'autore)

In questo tutorial, abbiamo creato una semplice applicazione React che esegue una singola chiamata al backend. Abbiamo racchiuso questa applicazione client come pacchetto Python e l'abbiamo servita dal nostro server web FastAPI Python.

L'utilizzo di questo approccio ti consente di sfruttare i migliori strumenti in entrambi i mondi: TypeScript e React per il frontend e Python con FastAPI per il backend. Tuttavia, vogliamo mantenere un’elevata coesione e un basso accoppiamento tra queste due componenti. In questo modo otterrai tutti i vantaggi:

  • Velocity, separando front-end e back-end in repository diversi, ogni parte può essere sviluppata da un team diverso.
  • Stabilità e qualità, bloccando un pacchetto client con versione e aggiornandolo solo quando il server è pronto a supportare una nuova versione client.
  • Sicurezza: il browser interagisce con un solo server backend. Non è necessario abilitare CORS o altre soluzioni alternative che compromettano la sicurezza.
  • Semplicità: lavorando tramite un unico server

Fonte: towardsdatascience.com

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *