App JS + backend Python: integration guidee

Publié le 2026-04-13

Objectif

L’objectif etait de transformer la page “App JS” en une vraie integration frontend + backend:

Le cas d’usage retenu: assistant de titre d’article.

L’utilisateur saisit un titre, puis l’application recupere:

1) Endpoint Python ajoute

Le backend expose un endpoint dedie:

@app.post("/tools/slugify")
def tool_slugify(payload: dict[str, str]) -> dict[str, str | int]:
    text = (payload.get("text") or "").strip()
    if not text:
        raise HTTPException(status_code=400, detail="text is required")

    if len(text) > 300:
        raise HTTPException(status_code=400, detail="text must be at most 300 characters")

    slug = sanitize_slug(text)
    words = count_words(text)
    read_minutes = max(1, math.ceil(words / 220))

    return {
        "input": text,
        "slug": slug,
        "word_count": words,
        "estimated_read_minutes": read_minutes,
    }

Points importants:

2) CORS active pour la communication cross-domain

Le frontend est servi par DOMAIN_SITE, l’API par DOMAIN_API. Il faut donc autoriser le navigateur a appeler l’API:

app.add_middleware(
    CORSMiddleware,
    allow_origins=CORS_ALLOWED_ORIGINS,
    allow_credentials=False,
    allow_methods=["GET", "POST", "OPTIONS"],
    allow_headers=["*"],
)

Variable utile cote infrastructure:

- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS:-*}

3) App JS remplacee dans Astro

La page apps/counter est devenue un formulaire interactif qui appelle l’API:

<input id="titleInput" type="text" maxlength="300" />
<button id="generateBtn">Generer</button>
<code id="slugOut"></code>

Puis appel reseau:

const response = await fetch(`${runtimeApiBaseUrl}/tools/slugify`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ text })
});

const payload = await response.json();

Et rendu du resultat:

slugOut.textContent = payload.slug;
wordCountOut.textContent = String(payload.word_count);
readTimeOut.textContent = String(payload.estimated_read_minutes);

4) URL API configurable et fallback runtime

La base URL API est configurable via PUBLIC_API_BASE_URL.

En plus, un fallback runtime derive automatiquement api. depuis site. si la valeur est encore par defaut.

Exemple:

const derivedHost = window.location.hostname.replace(/^site\./, "api.");
return `${window.location.protocol}//${derivedHost}`;

Resultat: integration plus robuste en environnement auto-heberge, meme si la variable n’a pas encore ete personnalisee.

5) Ajustements d’infrastructure

Build args et variables ajoutes:

PUBLIC_API_BASE_URL: "${PUBLIC_API_BASE_URL:-https://api.example.com}"
PUBLIC_API_BASE_URL=https://api.example.com
CORS_ALLOWED_ORIGINS=https://site.example.com

6) Verification rapide

Test backend direct:

curl -sS -X POST "https://${DOMAIN_API}/tools/slugify" \
  -H "Content-Type: application/json" \
  -d '{"text":"Titre utilisateur pour test backend"}'

Exemple de reponse:

{
  "input": "Titre utilisateur pour test backend",
  "slug": "titre-utilisateur-pour-test-backend",
  "word_count": 5,
  "estimated_read_minutes": 1
}

Conclusion

Ce lot montre un pattern simple et durable:

Ce type de micro-integration permet d’ajouter des outils utiles sans transformer le CMS en monolithe complexe.