Introduction
Google App Engine est une PaaS serverless qui gère l'infrastructure pour vous, idéale pour des APIs scalables sans ops. En 2026, avec l'environnement standard optimisé pour les workloads légers et flexible pour les customs, elle excelle en auto-scaling, zero-downtime deployments et intégration GCP native.
Ce tutoriel expert vous guide pas à pas pour déployer une API Node.js complète : routes sécurisées, intégration Firestore, queues tasks et monitoring. Pourquoi c'est crucial ? App Engine scale de 0 à des millions de req/s sans config manuelle, réduit les coûts via cold starts optimisés et intègre seamlessly avec Cloud Run pour hybrid.
On part d'un projet vide vers un setup prod : app.yaml avancé, versioning, traffic splitting. À la fin, votre API sera résiliente, observable et SEO-optimisée pour Learni Dev. Temps estimé : 30 min pour un deploy live. (128 mots)
Prérequis
- Compte Google Cloud Platform activé (facturation requise, quota App Engine standard)
- gcloud CLI installée et authentifiée (
gcloud auth login) - Node.js 20+ et npm/yarn
- Projet GCP existant (
gcloud config set project MON_PROJET) - Connaissances avancées en Node.js/Express et YAML
Initialiser le projet Node.js
mkdir api-app-engine
cd api-app-engine
npm init -y
npm install express @google-cloud/firestore cors helmet morgan
npm install --save-dev typescript @types/node @types/express @types/cors @types/helmet @types/morgan ts-node nodemon
npx tsc --initCette commande crée un projet Node.js avec Express pour l'API, Firestore pour la DB serverless, et sécurité (cors, helmet). Les dev deps activent TypeScript pour du code type-safe. Piège : oubliez gcloud app create si premier deploy dans le projet.
Configurer package.json pour prod
Adaptez package.json pour un démarrage optimisé en prod. Ajoutez des scripts pour local (npm run dev) et prod (npm start). Spécifiez engines.node pour matcher App Engine (Node 20+). Cela évite les cold starts lents.
package.json complet
{
"name": "api-app-engine",
"version": "1.0.0",
"description": "API scalable sur App Engine",
"main": "dist/server.js",
"scripts": {
"build": "tsc",
"start": "node dist/server.js",
"dev": "nodemon --exec ts-node server.ts"
},
"engines": {
"node": "20.x"
},
"dependencies": {
"express": "^4.19.2",
"@google-cloud/firestore": "^7.7.0",
"cors": "^2.8.5",
"helmet": "^7.1.0",
"morgan": "^1.10.0"
},
"devDependencies": {
"@types/node": "^22.5.5",
"@types/express": "^4.17.21",
"@types/cors": "^2.8.17",
"@types/helmet": "^4.0.0",
"@types/morgan": "^1.9.9",
"typescript": "^5.6.2",
"ts-node": "^10.9.2",
"nodemon": "^3.1.7"
}
}Ce package.json est prod-ready : build TS vers JS, engines lock Node version pour App Engine. Scripts isolent dev/prod. Piège : sans engines, App Engine peut downgrader Node et casser des deps.
Serveur Express avec Firestore
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import morgan from 'morgan';
import { Firestore, FieldValue } from '@google-cloud/firestore';
const app = express();
const PORT = process.env.PORT || 8080;
const firestore = new Firestore();
app.use(helmet());
app.use(cors({ origin: '*' }));
app.use(morgan('combined'));
app.use(express.json());
app.get('/health', (req, res) => res.status(200).json({ status: 'OK' }));
app.post('/items', async (req, res) => {
try {
const { name } = req.body;
if (!name) return res.status(400).json({ error: 'Name required' });
const docRef = firestore.collection('items').doc();
await docRef.set({ name, created: FieldValue.serverTimestamp() });
res.status(201).json({ id: docRef.id });
} catch (error) {
res.status(500).json({ error: 'Internal error' });
}
});
app.get('/items/:id', async (req, res) => {
try {
const doc = await firestore.collection('items').doc(req.params.id).get();
if (!doc.exists) return res.status(404).json({ error: 'Not found' });
res.json(doc.data());
} catch (error) {
res.status(500).json({ error: 'Internal error' });
}
});
app.listen(PORT, () => {
console.log(`Server on port ${PORT}`);
});Serveur TS complet avec routes CRUD Firestore, sécurité helmet/cors, logging morgan. Utilise process.env.PORT obligatoire pour App Engine. Piège : sans try/catch async, les erreurs crashent l'instance ; toujours logger en prod.
Compiler et tester localement
Exécutez npm run build puis npm start pour tester. Vérifiez /health, POST /items et GET /items/:id avec curl ou Postman. Analogie : comme un avion avant décollage, testez cold starts (kill puis relancez).
app.yaml pour standard environment
runtime: nodejs20
env: standard
env_variables:
NODE_ENV: "production"
GOOGLE_CLOUD_PROJECT: "votre-projet-id"
automatic_scaling:
min_instances: 1
max_instances: 100
target_cpu_utilization: 0.65
max_concurrent_requests: 100
handlers:
- url: /.*
script: auto
secure: always
redirect_http_response_code: 301
liveness_check:
path: "/health"
check_interval: 30s
timeout: 5s
failure_threshold: 3
success_threshold: 2
readiness_check:
path: "/health"
check_interval: 10s
timeout: 3s
failure_threshold: 3
success_threshold: 2app.yaml configure runtime Node20, scaling auto (1-100 instances, CPU 65%), health checks pour zero-downtime. Secure HTTPS only. Piège : sans min_instances:1, cold starts >1s latence ; ajustez pour votre trafic.
Premier déploiement
Créez l'app si besoin : gcloud app create --region=us-central. Puis gcloud app deploy. Accédez via gcloud app browse. Vérifiez logs : gcloud app logs tail -s default.
Script de déploiement automatisé
#!/bin/bash
PROJET="votre-projet-id"
VERSION="v1-$(date +%Y%m%d-%H%M%S)"
gcloud config set project $PROJET
git add .
git commit -m "Deploy $VERSION"
npm run build
gcloud app deploy --version=$VERSION --project=$PROJET
gcloud app services default versions list
gcloud app traffic default allocate --version=$VERSION --split=100Script bash pour build, deploy avec timestamp version, et route 100% traffic. Intégrez Git pour CI/CD. Piège : sans --version, overwrite crash traffic ; toujours nouvelle version pour rollback.
Traffic splitting multi-versions
gcloud app versions list --service=default
gcloud app traffic default allocate \
--split=v1=80 \
--split=v2=20
# Rollback
gcloud app traffic default shift v1 --version=v1Split 80/20 pour A/B testing sans downtime. shift migre progressivement. Piège : splits >2 versions fragmentent metrics ; limitez à 2-3 pour prod.
Intégration queues pour tâches async
Pour workloads lourds (ex: emails), ajoutez à app.yaml :
``yaml
dispatch:
- url: "/tasks/"
module: "default"
queue:
default:
rate: "100/m"
bucket_size: 10
`taskqueue.add(url='/tasks/process', payload=data)`.
Envoi :
.gcloudignore pour optimiser deploy
node_modules
npm-debug.log
.DS_Store
*.log
.nyc_output
coverage
.env
.nyc_output
.cache
*.tsbuildinfo
distIgnore node_modules (rebuild en env), logs, cache pour deploys <10s. Réduit bande passante 90%. Piège : oublier = deploys lents, timeouts.
Bonnes pratiques
- Scaling finetuning : Monitor CPU/RAM via Cloud Monitoring, ajustez
target_cpu_utilizationà 60-70% pour équilibre coût/perf. - Secrets management : Utilisez Secret Manager pour API keys (
gcloud secrets versions access), injectez via env_vars runtime config. - Observability : Activez Cloud Trace/Profiler ; structurez logs JSON pour BigQuery export.
- Migrez vers flexible si custom deps :
env: flex, dockerfile avecgcr.io. - Cost control : Set
max_instancesbas, utilisez F1 instances pour dev.
Erreurs courantes à éviter
- Port fixe : Toujours
process.env.PORT, App Engine force 8080. - Cold starts ignorés : Ajoutez
min_instances:1pour prod ; testez avecgcloud app instances delete. - Versions sans split : Deploy direct overwrite downtime ; toujours
--version+allocate. - Firestore sans index : Composite queries échouent ; créez via console ou
firestore.indexes.json.
Pour aller plus loin
- Docs officielles : App Engine Node.js
- Monitoring avancé : Cloud Operations
- CI/CD GitHub Actions : Intégrez
gcloud app deployworkflow.