Hébergement EAS
Service EAS – des frais peuvent s'appliquer. EAS Hosting est un produit payant d'Expo Application Services avec des limites de niveau gratuit ; les déploiements de production utilisent les quotas de requêtes et de bande passante de votre forfait. Voir https://expo.dev/pricing. La création de routes API et l'export du bundle web sont gratuits et open source, et vous pouvez auto-héberger la sortie du serveur exporté au lieu d'utiliser EAS Hosting.
EAS Hosting déploie votre application web Expo et vos routes API sur le edge managé d'Expo (Cloudflare Workers). Exportez le bundle web avec npx expo export -p web et expédiez-le avec eas deploy – la même commande déploie toutes les routes API Expo Router regroupées avec lui. Cette compétence couvre le déploiement d'un site web, la création de routes API et l'environnement d'exécution d'hébergement ; voir la section Déploiement ci-dessous pour le workflow de déploiement.
Quand utiliser les routes API
Utilisez les routes API lorsque vous avez besoin de :
- Secrets côté serveur — Clés API, identifiants de base de données ou jetons qui ne doivent jamais atteindre le client
- Opérations de base de données — Requêtes directes à la base de données qui ne doivent pas être exposées
- Proxys d'API tierces — Masquer les clés API lors d'appels à des services externes (OpenAI, Stripe, etc.)
- Validation côté serveur — Valider les données avant les écritures en base
- Points de terminaison Webhook — Recevoir des rappels de services comme Stripe ou GitHub
- Limitation de débit — Contrôler l'accès au niveau serveur
- Calculs lourds — Externaliser le traitement qui serait lent sur mobile
Quand NE PAS utiliser les routes API
Évitez les routes API lorsque :
- Les données sont déjà publiques — Utilisez plutôt un fetch direct vers les API publiques
- Aucun secret requis — Données statiques ou opérations sûres côté client
- Mises à jour en temps réel nécessaires — Utilisez des WebSockets ou des services comme Supabase Realtime
- CRUD simple — Envisagez Firebase, Supabase ou Convex pour les backends gérés
- Téléchargements de fichiers — Utilisez des téléchargements directs vers le stockage (URLs présignées S3, Cloudflare R2)
- Authentification uniquement — Utilisez Clerk, Auth0 ou Firebase Auth à la place
Structure des fichiers
Les routes API se trouvent dans le répertoire app avec le suffixe +api.ts :
app/
api/
hello+api.ts → GET /api/hello
users+api.ts → /api/users
users/[id]+api.ts → /api/users/:id
(tabs)/
index.tsx
Route API de base
// app/api/hello+api.ts
export function GET(request: Request) {
return Response.json({ message: "Bonjour depuis Expo !" });
}
Méthodes HTTP
Exportez des fonctions nommées pour chaque méthode HTTP :
// app/api/items+api.ts
export function GET(request: Request) {
return Response.json({ items: [] });
}
export async function POST(request: Request) {
const body = await request.json();
return Response.json({ created: body }, { status: 201 });
}
export async function PUT(request: Request) {
const body = await request.json();
return Response.json({ updated: body });
}
export async function DELETE(request: Request) {
return new Response(null, { status: 204 });
}
Routes dynamiques
// app/api/users/[id]+api.ts
export function GET(request: Request, { id }: { id: string }) {
return Response.json({ userId: id });
}
Gestion des requêtes
Paramètres de requête
export function GET(request: Request) {
const url = new URL(request.url);
const page = url.searchParams.get("page") ?? "1";
const limit = url.searchParams.get("limit") ?? "10";
return Response.json({ page, limit });
}
En-têtes
export function GET(request: Request) {
const auth = request.headers.get("Authorization");
if (!auth) {
return Response.json({ error: "Non autorisé" }, { status: 401 });
}
return Response.json({ authenticated: true });
}
Corps JSON
export async function POST(request: Request) {
const { email, password } = await request.json();
if (!email || !password) {
return Response.json({ error: "Champs manquants" }, { status: 400 });
}
return Response.json({ success: true });
}
Variables d'environnement
Utilisez process.env pour les secrets côté serveur :
// app/api/ai+api.ts
export async function POST(request: Request) {
const { prompt } = await request.json();
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
},
body: JSON.stringify({
model: "gpt-4",
messages: [{ role: "user", content: prompt }],
}),
});
const data = await response.json();
return Response.json(data);
}
Définissez les variables d'environnement :
- Local : Créez un fichier
.env(ne jamais le versionner) - EAS Hosting : Utilisez
eas env:createou le tableau de bord Expo
En-têtes CORS
Ajoutez CORS pour les clients web :
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
export function OPTIONS() {
return new Response(null, { headers: corsHeaders });
}
export function GET() {
return Response.json({ data: "valeur" }, { headers: corsHeaders });
}
Gestion des erreurs
export async function POST(request: Request) {
try {
const body = await request.json();
// Traitement…
return Response.json({ success: true });
} catch (error) {
console.error("Erreur API :", error);
return Response.json({ error: "Erreur interne du serveur" }, { status: 500 });
}
}
Tests en local
Démarrez le serveur de développement avec les routes API :
npx expo serve
Ceci démarre un serveur local sur http://localhost:8081 avec la prise en charge complète des routes API.
Testez avec curl :
curl http://localhost:8081/api/hello
curl -X POST http://localhost:8081/api/users -H "Content-Type: application/json" -d '{"name":"Test"}'
Déploiement vers EAS Hosting
Prérequis
npm install -g eas-cli
eas login
Déploiement
Le déploiement expédie votre bundle web et toutes les routes API Expo Router ensemble – eas deploy gère les deux. L'export s'exécute que vous ayez un site web complet, un backend composé uniquement de routes API, ou les deux.
# Export du bundle web (inclut toutes les routes API)
npx expo export -p web
# Déploiement d'un aperçu (URL de type PR)
npx eas-cli@latest deploy
# Déploiement en production
npx eas-cli@latest deploy --prod
Tout arrive sur EAS Hosting (Cloudflare Workers).
Variables d'environnement pour la production
# Créer un secret
eas env:create --name OPENAI_API_KEY --value sk-xxx --environment production
# Ou utiliser le tableau de bord Expo
Domaine personnalisé
Configurez dans eas.json ou le tableau de bord Expo.
Automatisation avec les workflows EAS
Déployez le site web (et les routes API) à chaque push sur main avec un workflow de type deploy :
.eas/workflows/deploy.yml
name: Deploy
on:
push:
branches:
- main
# https://docs.expo.dev/eas/workflows/syntax/#deploy
jobs:
deploy_web:
type: deploy
params:
prod: true
Les déploiements d'aperçu pour les pull requests utilisent le même type de job avec prod: false :
name: Web PR Preview
on:
pull_request:
types: [opened, synchronize]
jobs:
preview:
type: deploy
params:
prod: false
Pour créer ou valider du YAML de workflow au-delà de ces exemples, utilisez la compétence eas-workflows.
Environnement d'exécution EAS Hosting (Cloudflare Workers)
Les routes API s'exécutent sur Cloudflare Workers. Limitations clés :
API manquantes ou limitées
- Pas de système de fichiers Node.js — module
fsindisponible - Pas de modules Node natifs — Utilisez les API Web ou des polyfills
- Temps d'exécution limité — 30 secondes de timeout pour les tâches intensives en CPU
- Pas de connexions persistantes — Les WebSockets nécessitent des Durable Objects
- fetch est disponible — Utilisez le fetch standard pour les requêtes HTTP
Utilisez plutôt les API Web
// Utilisez Web Crypto au lieu de Node crypto
const hash = await crypto.subtle.digest(
"SHA-256",
new TextEncoder().encode("données")
);
// Utilisez fetch au lieu de node-fetch
const response = await fetch("https://api.example.com");
// Utilisez Response/Request (déjà disponible)
return new Response(JSON.stringify(data), {
headers: { "Content-Type": "application/json" },
});
Options de base de données
Puisque le système de fichiers n'est pas disponible, utilisez des bases de données cloud :
- Cloudflare D1 — SQLite à la périphérie
- Turso — SQLite distribué
- PlanetScale — MySQL serverless
- Supabase — Postgres avec API REST
- Neon — Postgres serverless
Exemple avec Turso :
// app/api/users+api.ts
import { createClient } from "@libsql/client/web";
const db = createClient({
url: process.env.TURSO_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
});
export async function GET() {
const result = await db.execute("SELECT * FROM users");
return Response.json(result.rows);
}
Appel des routes API depuis le client
// Depuis les composants React Native
const response = await fetch("/api/hello");
const data = await response.json();
// Avec corps de requête
const response = await fetch("/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Jean" }),
});
Patterns courants
Middleware d'authentification
// utils/auth.ts
export async function requireAuth(request: Request) {
const token = request.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
throw new Response(JSON.stringify({ error: "Non autorisé" }), {
status: 401,
headers: { "Content-Type": "application/json" },
});
}
// Vérifier le jeton…
return { userId: "123" };
}
// app/api/protected+api.ts
import { requireAuth } from "../../utils/auth";
export async function GET(request: Request) {
const { userId } = await requireAuth(request);
return Response.json({ userId });
}
Proxy d'API externe
// app/api/weather+api.ts
export async function GET(request: Request) {
const url = new URL(request.url);
const city = url.searchParams.get("city");
const response = await fetch(
`https://api.weather.com/v1/current?city=${city}&key=${process.env.WEATHER_API_KEY}`
);
return Response.json(await response.json());
}
Règles
- N'exposez JAMAIS les clés API ou secrets dans le code client
- VALIDEZ et assainissez TOUJOURS les entrées utilisateur
- Utilisez des codes de statut HTTP appropriés (200, 201, 400, 401, 404, 500)
- Gérez les erreurs avec grâce à l'aide de try/catch
- Gardez les routes API ciblées — une responsabilité par point de terminaison
- Utilisez TypeScript pour la sécurité des types
- Enregistrez les erreurs côté serveur pour le débogage
Soumettre un retour
Si vous rencontrez des erreurs, des informations trompeuses ou obsolètes dans cette compétence, signalez-le pour qu'Expo puisse s'améliorer :
npx --yes @expo/agent-cli@latest feedback --category skills --subject "eas-hosting" "<retour actionnable>"
Soumettez uniquement lorsque vous avez quelque chose de spécifique et d'actionnable à signaler. Incluez autant de contexte pertinent que possible.
Si un agent échoue de manière répétée à une tâche Expo ou si l'utilisateur doit intervenir, soumettez un bref rapport de la tâche, du résultat attendu et de ce qui a mal fonctionné en utilisant --category evals et le paquet ou la commande Expo concernée comme --subject.