Fix Init Admin : Séparation page HTML et endpoint API
Fix Init Admin : Séparation page HTML et endpoint API
Documentation de la résolution de l'erreur réseau lors de la création d'un admin via l'endpoint init-admin.
Correction de l’erreur Init Admin : Séparation page HTML et endpoint API
1. Description du Problème
Lors de la création d’un utilisateur administrateur via l’URL https://amn-dev.anderson-metsanou.workers.dev/api/auth/init-admin, le client recevait une erreur “Erreur réseau ou serveur indisponible” alors que les logs Cloudflare montraient un statut 200 OK.
Logs Cloudflare :
{ "statusCode": 200, "outcome": "ok", "path": "/api/auth/init-admin"}Erreur client :
Erreur réseau ou serveur indisponibleTest local curl :
curl -X POST http://localhost:8787/api/auth/init-admin \ -H "Content-Type: application/json" \ -d '{"email":"test@test.com","password":"password123","name":"Test Admin"}'Résultat : Retourne du HTML au lieu du JSON
2. Analyse de la Cause Racine1/2
-
Fichier unique mélangeant HTML et API :
src/pages/api/auth/init-admin.astroétait un fichier Astro qui rendait du HTML- Quand on faisait un POST, Astro continuait à rendre la page HTML au lieu de traiter la requête API
2. Analyse de la Cause Racine2/2
-
Content-Type incorrect :
- La réponse avait
Content-Type: text/htmlau lieu deapplication/json - Le client ne pouvait pas parser le HTML comme JSON
- La réponse avait
-
Structure de fichier Astro :
- Les fichiers
.astrodanssrc/pages/api/auth/sont traités comme des pages - Ils rendent toujours du HTML, même pour les requêtes POST
- Les fichiers
3. Solution Appliquée
Séparation des responsabilités :
-
Déplacer la page HTML :
- Déplacer
src/pages/api/auth/init-admin.astroverssrc/pages/init-admin.astro - Cette page servira uniquement l’interface utilisateur à
/init-admin
- Déplacer
-
Créer l’endpoint API dédié :
- Créer
src/pages/api/auth/init-admin.tspour gérer les requêtes POST - Ce fichier retourne uniquement du JSON
- Créer
Nouvelle structure :
Page HTML (src/pages/init-admin.astro) :
- Rend l’interface utilisateur pour créer un admin
- Accessible via
/init-admin - Contient le formulaire et le script client
Endpoint API (src/pages/api/auth/init-admin.ts) :
- Gère les requêtes POST à
/api/auth/init-admin - Retourne du JSON avec la réponse Better Auth
- Contient uniquement la logique serveur
Code de l’endpoint API (src/pages/api/auth/init-admin.ts) :1/2
Code de l’endpoint API (src/pages/api/auth/init-admin.ts) :2/2
import type { APIRoute } from 'astro';import { createAuth } from '../../../auth/index';
export const prerender = false;
async function getEnv() { try { const { env } = await import('cloudflare:workers'); return env; } catch (_e) { return null; }}
export const POST: APIRoute = async (context) => { try { const env = await getEnv();
if (!env) { return new Response(JSON.stringify({ error: 'Cloudflare environment not available' }), { status: 500, headers: { 'Content-Type': 'application/json' } }); }
const body = await context.request.json(); const { email, password, name } = body as { email?: string; password?: string; name?: string };
if (!email || !password) { return new Response(JSON.stringify({ error: 'Email and password are required' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); }
const auth = createAuth(env);
const result = await auth.api.signUpEmail({ body: { email, password, name: name || email.split('@')[0] } });
return new Response(JSON.stringify({ success: true, user: result }), { status: 200, headers: { 'Content-Type': 'application/json' } }); } catch (err) { console.error('[Init admin error]', err); return new Response(JSON.stringify({ error: 'Internal server error', message: err instanceof Error ? err.message : String(err) }), { status: 500, headers: { 'Content-Type': 'application/json' } }); }};Correction des imports dans la page HTML :1/2
Avant :
---import BaseHead from '../../../components/BaseHead.astro';import Header from '../../../components/Header.astro';import Footer from '../../../components/Footer.astro';---Correction des imports dans la page HTML :2/2
Après :
---import BaseHead from '../components/BaseHead.astro';import Header from '../components/Header.astro';import Footer from '../components/Footer.astro';---4. Références Astro
Selon la documentation Astro sur le routing :
- Les fichiers dans
src/pages/avec l’extension.astrosont des pages qui rendent du HTML - Les fichiers API doivent avoir l’extension
.tsou.jspour retourner du JSON - Les fichiers dans
src/pages/api/avec.astrosont toujours traités comme des pages HTML
Structure correcte pour les APIs :
- Pages HTML :
src/pages/nom-page.astro→ rend HTML - Endpoints API :
src/pages/api/nom-endpoint.ts→ retourne JSON
5. Tests de Validation
Test après correction :
- Build local : ✅ Succès
- Test endpoint API : À tester avec curl
- Déploiement : À tester via GitHub Actions
- Création admin : À tester sur l’URL déployée
Test curl attendu :1/2
curl -X POST http://localhost:8787/api/auth/init-admin \ -H "Content-Type: application/json" \ -d '{"email":"test@test.com","password":"password123","name":"Test Admin"}'Test curl attendu :2/2
Résultat attendu :
{ "success": true, "user": { "email": "test@test.com", "name": "Test Admin", "id": "..." }}6. Leçons Apprises1/2
-
Séparation des responsabilités :
- Les pages HTML et les endpoints API doivent être dans des fichiers séparés
- Les fichiers
.astrodanssrc/pages/api/sont traités comme des pages HTML
6. Leçons Apprises2/2
-
Structure de fichiers Astro :
- Les fichiers API doivent avoir l’extension
.tsou.js - Les fichiers
.astrosont réservés au rendu HTML
- Les fichiers API doivent avoir l’extension
-
Tests d’API :
- Toujours tester les endpoints avec curl avant de les utiliser dans le frontend
- Vérifier le Content-Type de la réponse