cartes

Les outils

API

Pour intégrer cartes à un autre logiciel : l'API HTTP rend les services de la ligne de commande — chercher une commune, lister les fonds et les couches, estimer, générer — à un programme plutôt qu'à une personne.

Le projet ne met aucune instance à disposition : chacun lance la sienne, sur son ordinateur, sur un serveur ou chez un hébergeur. Ce qu'une instance reçoit — la commune, les données ajoutées — reste chez celui qui l'héberge.

Lancer une instance#

Avec Node.js 22 ou plus récent, depuis le dépôt :

npm install
npm start               # ou : cartes serveur --port 8080

L'instance écoute sur le port donné par --port, sinon par la variable PORT, sinon sur le 8080. Elle ne répond qu'à la machine où elle tourne, sur 127.0.0.1 : --hote 0.0.0.0, ou la variable CARTES_HOTE=0.0.0.0, l'ouvre au réseau. Un hébergeur l'exige, et une instance ouverte au réseau devrait exiger une clé. Elle se décrit elle-même : GET / donne sa version et dit si une clé est exigée, GET /openapi.json donne sa description OpenAPI complète.

Réglages#

Chaque réglage passe par une variable d'environnement. Ce qui ferait tomber l'instance est limité d'office : la mémoire d'une génération, la file d'attente, les adresses de son propre réseau. Le reste ne l'est que si on le demande :

Variable Effet Par défaut
CARTES_HOTE adresse d'écoute, comme --hote ; 0.0.0.0 ouvre l'instance au réseau 127.0.0.1 : cette machine seulement
CARTES_CLE_API clé exigée dans l'en-tête Authorization: Bearer <clé> aucune : l'API répond à tous
CARTES_ZOOM_MAX zoom le plus élevé accepté celui de chaque fond de carte, 19
CARTES_MEMOIRE_MAX mémoire, en Mo, que peut occuper la génération d'une carte ; une carte qui en demande plus est refusée celle de la machine ou de son conteneur, moins ce que l'instance occupe déjà, partagée entre les générations simultanées
CARTES_GENERATIONS nombre de cartes générées en même temps ; les suivantes attendent leur tour 1
CARTES_EN_ATTENTE nombre de cartes qui peuvent attendre leur tour ; au-delà, la demande reçoit le code 503 10
CARTES_CONSERVATION durée, en minutes, pendant laquelle une carte reste téléchargeable 60
CARTES_SORTIES dossier où les cartes sont écrites un dossier cartes dans le dossier temporaire
CARTES_COUCHES_PERSO non refuse les couches ajoutées par leur adresse (couchesPerso) oui : acceptées, sur le réseau public seulement

Une couche ajoutée par son adresse est téléchargée par l'instance, au nom de celui qui la demande. L'instance refuse donc toute adresse de son propre réseau : la boucle locale, les réseaux privés, l'adresse où un hébergeur sert les informations de ses machines. Elle le vérifie au moment de se connecter, après avoir résolu le nom, et à chaque redirection. Une couche publiée sur un intranet s'ajoute dans l'application de bureau ou en ligne de commande, qui consultent toutes les adresses.

Le cache des tuiles se règle comme pour la ligne de commande, avec --cache (.cache/tiles par défaut), et le nombre de téléchargements simultanés de chaque carte avec --paralleles (6).

Combien de mémoire ?#

Une génération occupe environ quatre fois la mémoire de l'image, que l'estimation indique. Mesuré sur Colombiers (Vienne), une commune de taille moyenne :

Zoom Image Mémoire occupée Durée, tuiles en cache
16 5 104 × 3 904 px 490 Mo 2 s
17 10 207 × 7 807 px 1 Go 6 s

Comptez donc au moins 2 Go pour le zoom 17, et bien plus pour les zooms 18 et 19. Deux cartes générées en même temps additionnent leur mémoire : c'est pourquoi CARTES_GENERATIONS vaut 1 par défaut.

L'instance refuse d'elle-même une carte dont la génération dépasserait sa mémoire, quatre fois celle de l'image, et le dit dans l'erreur. Le zoom n'est pas seul en cause : une marge élargit l'image tout autant. Par défaut, elle compte la mémoire de la machine, ou celle de son conteneur si elle est plus petite. CARTES_MEMOIRE_MAX la fixe quand l'instance partage sa machine avec d'autres programmes. CARTES_ZOOM_MAX reste utile pour annoncer une limite simple aux logiciels qui appellent l'API.

Les services#

Chaque chemin a un alias anglais, entre parenthèses.

Service Effet
GET /communes?nom=…&departement=… (/municipalities?name=…&department=…) chercher une commune par son nom
GET /fonds (/basemaps) lister les fonds de carte
GET /couches (/maplayers) lister les couches superposables, avec leur thème (urbanisme, risques ou territoire), qui les publie et, s'il y en a un, le zoom à partir duquel elles se dessinent (zoomMin)
POST /estimations (/estimates) pour chaque zoom, les dimensions, le format papier et la mémoire ; pour le zoom demandé, le poids estimé du fichier
POST /cartes (/maps) demander une carte
GET /cartes/{id} suivre une carte : statut, avancement, avertissements
GET /cartes/{id}/fichier (/maps/{id}/file) télécharger une carte terminée
DELETE /cartes/{id} annuler une carte, ou supprimer une carte terminée et son fichier

Une erreur est renvoyée en JSON, décrite en français : { "erreur": "Fond inconnu : …" }, avec le code 400 pour une demande incorrecte ou une carte trop grande pour la mémoire de l'instance, 401 pour une clé absente ou invalide, 404 pour une carte inconnue ou expirée, 409 pour une carte pas encore prête, 413 pour une demande trop volumineuse, au-delà de 21 Mo, et 503 quand la file d'attente est pleine. La description OpenAPI, sur /openapi.json, donne la réponse de chaque service, champ par champ.

Demander une carte#

Générer une carte prend de quelques secondes à plusieurs minutes. La demande ne l'attend donc pas : elle est acceptée tout de suite, puis suivie, puis téléchargée.

# 1. La demande, acceptée avec le statut 202 et l'identifiant de la carte
curl -X POST http://localhost:8080/cartes \
  -H 'Content-Type: application/json' \
  -d '{ "commune": "86081", "zoom": 16, "couches": ["cadastre"] }'

# 2. Le suivi, jusqu'au statut « terminée »
curl http://localhost:8080/cartes/<id>

# 3. Le fichier
curl -OJ http://localhost:8080/cartes/<id>/fichier

Le suivi renvoie le statut — en attente, en cours, terminée, échouée ou annulée, et supprimée en réponse à la suppression —, l'avancement de chaque source en tuiles — et celui des dates des données, lues dans le catalogue pour la mention des sources, sous dates —, les etapes franchies, les avertissements et, en cas d'échec, l'erreur. Une carte terminée reste téléchargeable jusqu'à son expiration, puis disparaît avec son fichier.

Les champs d'une demande#

Ce sont les options de cartes generer, en JSON. Chacun accepte aussi un nom anglais : municipality, department, basemap, zoom, maplayers, customLayers, data, dataCategory, dataColor, format, margin, dpi, grayscale, outline, legend. Les champs d'une couche, d'une couche ajoutée par son adresse et d'un fichier en ont un aussi : opacity ; url, layer, name, attribution, opacity ; fileName, title, content. Un champ inconnu est refusé, pour qu'une faute de frappe ne passe pas inaperçue.

Champ Effet Par défaut
commune nom ou code INSEE — obligatoire
departement département, pour lever une homonymie
fond fond de carte, voir GET /fonds plan-ign
zoom niveau de zoom, qui décide de la taille de l'image 17
couches couches à superposer : ["cadastre"], ou [{ "id": "cadastre", "opacite": 0.4 }] aucune
couchesPerso couches ajoutées par leur adresse : [{ "adresse": "https://…/{z}/{x}/{y}.pbf", "nom": "…", "source": "…" }], ou par celle d'un service WMS et le nom de sa couche : [{ "adresse": "https://…/wms", "couche": "…", "nom": "…", "source": "…" }] aucune
donnees fichiers de données, en texte : [{ "fichier": "points.geojson", "contenu": "…" }], avec un titre facultatif. Un CSV d'adresses se géocode d'abord, avec cartes geocoder aucun
donneesCategorie, donneesCouleur propriétés qui portent la catégorie et la couleur des objets
format png, jpg ou tif celui du fond de carte
marge marge autour de la commune 0.03
dpi résolution d'impression visée 150
gris fond de carte en niveaux de gris false
contour tracer le contour de la commune true
legende afficher la légende des données ajoutées true

POST /estimations prend les mêmes champs. La ligne de commande et l'ajout de données en disent plus sur chacun.

Ce qui ne changera pas#

À partir de la version 1.0.0, les chemins, les champs des demandes et des réponses — sous leurs noms français et anglais —, les codes de réponse et les identifiants du catalogue ne changent pas sans une version majeure. Une version mineure peut ajouter un champ, un service ou une couche, jamais en retirer ni en renommer : un logiciel qui lit les réponses doit tolérer un champ qu'il ne connaît pas. La description OpenAPI de l'instance, sur /openapi.json, fait foi.

Déployer sur Clever Cloud#

Clever Cloud reconnaît une application Node.js et la lance par npm start, sur le port que donne sa variable PORT. Elle doit écouter sur toutes ses interfaces : CARTES_HOTE=0.0.0.0 est indispensable, sans quoi Clever Cloud ne la joint pas. Avec l'outil en ligne de commande clever-tools, depuis le dépôt :

clever create -t node cartes-api
clever scale --instances 1
clever env set CARTES_HOTE 0.0.0.0                        # indispensable
clever env set CARTES_CLE_API "$(openssl rand -hex 24)"   # facultatif
clever env set CARTES_ZOOM_MAX 17                         # facultatif
clever deploy

Quelques particularités à connaître :

Quelle taille d'instance ?#

Mesuré sur Clever Cloud en septembre 2026, avec la carte de Colombiers (Vienne), une commune de taille moyenne, en PNG. Chaque case donne deux ordres de grandeur, d'après la plus longue des mesures : la durée sans aucune tuile de ce zoom en cache, puis celle de la même carte redemandée, les tuiles déjà en cache.

Zoom Image Mémoire XS (1 Go) S (2 Go) M (4 Go) XL (16 Go)
15 2 553 × 1 953 px 15 Mo ✅ < 30 s, puis < 5 s ✅ < 1 min, puis < 10 s ✅ < 10 s, puis < 5 s ✅ comme M
16 5 104 × 3 904 px 60 Mo ✅ < 30 s, puis < 10 s ✅ < 1 min, puis < 10 s ✅ < 30 s, puis < 5 s ✅ comme M
17 10 207 × 7 807 px 239 Mo ❌ instance figée ⚠️ < 2 min, puis < 10 s ✅ < 1 min, puis < 10 s ✅ comme M
18 20 413 × 15 614 px 956 Mo non essayé ❌ instance figée ⚠️ < 4 min, puis < 30 s ⚠️ comme M
19 40 824 × 31 227 px 3,8 Go non essayé non essayé ❌ déduit de la L ⚠️ < 30 min, puis < 2 min

✅ la carte sort en moins d'une minute sans cache ; ⚠️ elle sort, mais peut dépasser la minute ; ❌ elle ne sort pas. « Mémoire » est celle de l'image seule, non compressée : l'instance en consomme davantage pendant l'assemblage et l'encodage. « Instance figée » : l'instance, à court de mémoire, cesse de répondre. Sur une XS au zoom 17, la carte est une fois sortie au bout de deux minutes et demie ; une autre fois, Clever Cloud a jugé l'instance injoignable et l'a redémarrée, et la carte a été perdue. Sur une S au zoom 18, rien n'était sorti après dix minutes. Au zoom 19, une L (8 Go) a été redémarrée de la même façon au bout d'un quart d'heure : l'image seule remplit déjà presque une M, et il faut une XL.

Une XL ne va pas plus vite qu'une M aux zooms qu'une M tient : aux zooms 17 et 18, les durées avec cache sont les mêmes, et sans cache c'est la Géoplateforme qui décide.

Les durées sans cache dépendent surtout de la Géoplateforme, qui sert les tuiles plus ou moins vite selon l'heure : d'une série de mesures à l'autre, elles ont varié du simple au quadruple. Les durées avec cache, elles, sont stables.

En résumé, réglez CARTES_ZOOM_MAX d'après la taille choisie :

Pour une commune plus étendue que Colombiers, comparez la mémoire que donne POST /estimations à celle du tableau.

Aller plus loin : une passerelle d'API#

CARTES_CLE_API protège une instance d'une seule clé, partagée par tous ceux qui l'appellent. Dès que plusieurs logiciels s'en servent, une passerelle d'API fait mieux : une clé par logiciel, que l'on peut retirer sans toucher aux autres, des quotas et une limite de débit pour chacun, des statistiques d'usage. L'instance n'a pas à le faire elle-même.

Otoroshi, la passerelle libre développée par la MAIF, s'y prête bien, et Clever Cloud la propose toute prête :

clever addon create otoroshi cartes-passerelle

Dans Otoroshi, une route renvoie alors vers l'adresse de l'instance, et chaque logiciel reçoit sa propre clé.

Gardez tout de même CARTES_CLE_API sur l'instance : sur Clever Cloud, elle reste joignable à son adresse cleverapps.io, et sans clé on pourrait contourner la passerelle en l'appelant directement. La clé de l'instance devient un secret que seule la passerelle connaît. Configurez la route pour qu'elle ajoute l'en-tête Authorization: Bearer <clé> à chaque requête transmise, à la place de celui du logiciel client.