Aller au contenu

API de cartes

Une carte rendue utilise trois choses de la passerelle : des tuiles vectorielles, un document de style qui explique comment les dessiner, et les polices/icônes référencées par ce style. @unmap/sdk et @unmap/maps récupèrent tout cela pour vous. Cette page sert à appeler la passerelle directement, ou à comprendre ce que fait votre carte en coulisse. Si tuile, style et zoom sont des mots nouveaux, le glossaire d'une minute les définit d'abord.

Le fond vectoriel par défaut est la publication planétaire Protomaps 20260922; il couvre le monde aux zooms Web Mercator de 0 à 14. L'archive canadienne est conservée pour un retour arrière. Le relief est mondial depuis la publication 6; les courbes de niveau restent limitées au Canada.

Les tuiles, les styles, le relief, les courbes de niveau, les glyphes et les sprites acceptent Authorization: Bearer <key>, X-API-Key: <key> ou ?key=<key>. Les URL générées dans les styles utilisent le paramètre de requête; les appels directs peuvent utiliser l'un ou l'autre des en-têtes. Voir Authentification.

Si c'est la carte qui vous intéresse et non les points de terminaison, rien de ceci n'est obligatoire :

npm i @unmap/sdk

Tuiles

GET /tiles/{z}/{x}/{y}

Un carré de données cartographiques. z est le niveau de zoom, x et y sont la colonne et la ligne du carré à ce zoom, donc /tiles/11/375/685 est un morceau du centre-ville de Calgary. Les carrés contiennent des données plutôt qu'une image de carte, au format Mapbox Vector Tile (application/x-protobuf), découpés dans une archive mondiale en projection Web Mercator des zooms 0 à 14. Un suffixe .pbf ou .mvt sur y est accepté et retiré, car les clients l'ajoutent de façon inconsistante.

curl "https://api.unmap.dev/tiles/11/375/685.mvt?key=$UNMAP_API_KEY" -o tile.mvt

Quatre choses à savoir :

  • Une réponse vide est 204 No Content, pas 404. Vous obtenez un 204 au-delà du zoom 14, et aussi à l'intérieur de la plage de zooms partout où l'archive ne contient aucune tuile, par exemple certaines tuiles océaniques vides. Les deux cas sont un vide légitime et non un échec. Au-delà du zoom 14, MapLibre continue de dessiner en agrandissant la tuile la plus profonde dont il dispose, ce qu'on appelle le surzoom, donc un 404 serait à la fois faux et bruyant.
  • Des coordonnées mal formées (z, x ou y non entiers) retournent 400 avec un corps texte, invalid tile coordinates, et non du JSON. Une colonne hors de 0 .. 2^z-1 est le même 400 : la colonne demandée est celle qui est lue. Les requêtes de tuiles, de terrain, de courbes de niveau, de glyphes et de sprites rejettent toutes une entrée mal formée en texte brut. Une publication de fond de carte absente, ci-dessous, est aussi du texte brut. Tout le reste de la passerelle répond en JSON. Voir Erreurs.
  • Une tuile qui a des octets est servie avec Cache-Control: public, max-age=86400. Un 204 n'est pas écrit dans le cache du Worker et n'envoie pas cet en-tête.
  • Un déploiement qui nomme une publication de fond de carte qui n'est pas un identifiant à huit chiffres, ou dont l'objet n'est pas dans le stockage, répond 503 avec le corps en texte brut basemap release is misconfigured et Cache-Control: private, no-store. Cette réponse ne sert pas l'archive précédente et n'est pas un 204 vide. Sur /tiles/{release}/{z}/{x}/{y}, un identifiant à huit chiffres qui n'a jamais été copié est un 404 basemap release not found, lui aussi private, no-store. Un identifiant qui n'a pas huit chiffres a le même corps 404 sans cet en-tête de cache. Réessayer ne rétablit pas l'archive précédente.

Les tuiles qui ont des octets sont mises en cache en périphérie avec la chaîne de requête (donc la clé) retirée de la clé de cache, donc la même tuile identique octet pour octet est partagée entre tous les clients plutôt que chacun réchauffant sa copie privée. Un 204 vide n'est pas stocké dans ce cache.

Styles

GET /styles/{style}.json?mode=&lang=&theme=&overlays=&profile=

Retourne un document de style MapLibre GL complet (version 8) : sources, couches, et des URL tiles, glyphs et sprite autoréférentielles qui pointent déjà vers cette passerelle, avec votre clé dans leurs chaînes de requête. Pointez MapLibre sur cette seule URL et il découvre le reste tout seul. Passez overlays= pour composer des couches du catalogue canadien, ou une superposition GeoJSON byod:<id> que vous avez téléversée (voir Apportez vos propres données), ou profile=energy / agriculture / remote / mining pour un préréglage de composition (overlays= explicite remplace la liste du profil). Couches est le catalogue; Énergie, Agriculture, Éloigné et Minier sont les préréglages.

Le voici, animant une vraie carte. Chaque contrôle modifie un seul élément de l'URL :

résultat en direct
le code qui l'a produit
import { Unmap } from "@unmap/sdk";

const unmap = new Unmap({
  key: "um_live_...",
  container: "map",
  style: "base",
  mode: "light",
  lang: "fr",
  center: [-114.0719, 51.0447],
  zoom: 11,
});
curl "https://api.unmap.dev/styles/outdoor.json?mode=dark&key=$UNMAP_API_KEY"

{style} est l'un des quinze styles ci-dessous. Un nom composé <style>-<mode> fonctionne aussi : /styles/outdoor-dark.json et /styles/outdoor.json?mode=dark sont la même requête. Un nom non reconnu retourne 404, en énumérant les noms qui existent :

{
  "error": "unknown style",
  "code": "not_found",
  "styles": ["base", "muted", "outdoor", "blueprint", "blush", "orchid", "canopy", "lagoon", "tropic", "sunset", "bold", "pastel", "atlas", "swiss", "winter"],
}

Ce que vous recevez

{
  "version": 8,
  "glyphs": "https://api.unmap.dev/glyphs/2/{fontstack}/{range}.pbf?key=...",
  "sprite": "https://api.unmap.dev/sprite/2/light?key=...",
  "sources": {
    "unmap": {
      "type": "vector",
      "tiles": ["…/tiles/{z}/{x}/{y}?key=..."],
      "maxzoom": 14,
    },
    "unmap_dem": {
      "type": "raster-dem",
      "encoding": "terrarium",
      "maxzoom": 12,
    },
    "unmap_contours": { "type": "vector", "minzoom": 9, "maxzoom": 14 },
  },
  "layers": [
    /* la cartographie, dans l'ordre de dessin */
  ],
  "center": [-114.0719, 51.0447],
  "zoom": 11,
}

Tant que BASEMAP_RELEASE n'est pas défini, unmap n'a pas de bounds et le modèle d'URL des tuiles est /tiles/{z}/{x}/{y}. Lorsque l'objet de cette publication est lisible, le modèle est /tiles/{release}/{z}/{x}/{y} et bounds vaut [-180, -85.0511287, 180, 85.0511287]. unmap_landcover, sur tous les styles sauf muted, reprend le modèle et les bounds de unmap et fixe maxzoom à 7. Les bounds du relief suivent la version active du MNE; les courbes gardent la fenêtre canadienne.

unmap est toujours présente. unmap_dem et unmap_contours n'apparaissent que pour outdoor, atlas, swiss et winter, et seulement une fois qu'une archive est configurée derrière chacune sur la passerelle ; un style n'annonce jamais une source sans rien derrière. center et zoom donnent une vue de départ centrée sur Calgary, donc un document de style est un plan d'ouverture complet et pas seulement une cartographie. Réglez la caméra avec les propres center et zoom de MapLibre.

Le document de style lui-même est généré à chaque requête. La réponse porte Cache-Control: private, no-store : elle contient la clé d'API et le modèle d'URL des tuiles de ce déploiement, donc un cache partagé ne la conserve pas. Une réponse qui porte des octets de tuile, de terrain, de courbe, de glyphe ou de sprite est mise en cache. Un 204 vide ne l'est pas.

Les quinze styles

Un style est l'une des quinze cartes structurelles; un mode vaut light ou dark. Chaque style est livré dans les deux, et les deux axes sont indépendants : un nom composé <style>-<mode> et un nom nu accompagné de ?mode= veulent dire la même chose.

  • base-light (défaut), base-dark : usage général. Hiérarchie routière complète, bâtiments visibles, couverture du sol assez différenciée pour se lire comme un terrain. base-dark rend l'eau plus sombre que la terre, ce qui empêche une carte sombre de s'effondrer en bouillie.
  • muted-light, muted-dark : niveaux de gris de bout en bout, eau et icônes comprises. Conçu pour disparaître sous les données que vous dessinez par-dessus.
  • outdoor-light, outdoor-dark : terrain d'abord, avec un ombrage DEM, des courbes de niveau et des sentiers.
  • blueprint-light, blueprint-dark : une seule famille de bleus. Un champ bleu roi aux routes marine en sombre, des lignes bleues sur papier bleu-blanc en clair.
  • blush-light, blush-dark : terre rose sur fond pêche, bâtiments rose foncé ; lie-de-vin la nuit.
  • orchid-light, orchid-dark : terre lavande, parcs sarcelle, bois menthe et eau ciel.
  • canopy-light, canopy-dark : terre fauve sous des verts de forêt profonds, routes quasi noires, bâtiments argile et eau bleu franc.
  • lagoon-light, lagoon-dark : terre vert pâle, eau aqua, parcs sarcelle, étiquettes grises.
  • tropic-light, tropic-dark : eau sarcelle à pleine force, parcs vert printemps, terre crème, autoroute corail. D'après les palettes Tropic et Temps de CARTO.
  • sunset-light, sunset-dark : un bichrome chaud. Terre crème, végétation pêche, routes corail, eau indigo ; crépuscule en sombre. D'après Sunset de CARTO.
  • bold-light, bold-dark : la carte de rues saturée. Eau bleu franc, parcs vert feuille, bois émeraude, autoroute ambre. D'après Bold et Vivid de CARTO.
  • pastel-light, pastel-dark : terre blanc lavande, eau pervenche, parcs menthe, autoroute saumon. D'après Pastel de CARTO.
  • atlas-light, atlas-dark : papier chaud, eau bleue, routes rouges, noms en caractères à empattements, relief et courbes de niveau. D'après Bay Atlas.
  • swiss-light, swiss-dark : fond blanc, eau bleu pâle, routes jaunes, voies ferrées rouges et relief plus marqué. D'après le style Swiss de Bay Atlas.
  • winter-light, winter-dark : terre blanche de neige, eau bleu glace, forêts d'épinettes et autoroute bleu froid, avec ombrage du relief et courbes de niveau. Conçu pour la superposition ski, dont les couleurs de pistes sont le contenu; le mode sombre est la même carte la nuit.

Un nom de style nu signifie ce style en mode clair, donc /styles/muted.json est une requête valide.

Un nom inconnu est un 404 not_found qui liste les vrais.

Mode

Le style et le mode sont deux axes distincts, vous pouvez donc aussi les envoyer séparément :

GET /styles/base.json?mode=dark&lang=en

?mode= choisit la moitié claire ou sombre de ce que le chemin a nommé, et il l'emporte sur un mode porté par le chemin : /styles/base-light.json?mode=dark donne base-dark. Préférez le nom nu accompagné de ?mode= si votre application a une bascule de thème, car changer un seul paramètre vaut mieux que recomposer un nom composé à chaque bascule. Un mode non reconnu n'est pas un 400 : le style est servi en mode clair, y compris lorsque le chemin nommait le mode sombre.

Terrain et courbes de niveau

Les styles outdoor, atlas, swiss et winter ajoutent une source raster-dem et, par-dessus, une source vectorielle de courbes de niveau. Vous n'avez normalement pas à les demander vous-même : le document de style porte déjà leurs URL avec votre clé, et MapLibre les requiert au fil du dessin. Elles sont indiquées ici pour que vous puissiez les reconnaître dans un journal réseau :

Les styles utilisent le relief mondial de la publication 6 :

GET /terrain/6/{z}/{x}/{y}.webp?key=...  # Terrarium/512, z0–12
GET /contours/4/{z}/{x}/{y}?key=...      # courbes canadiennes, z9–13

Après un retour arrière, le relief revient à /terrain/4/...png. Cette archive sert le relief canadien quand TERRAIN_RELEASE n'est pas défini. Les URL versionnées identifient leur propre archive; les publications inconnues donnent 404. La représentation WebP répond image/webp, la PNG image/png et les courbes application/x-protobuf. Les tuiles absentes ou hors plage de zoom donnent 204. Une publication active indisponible répond 503 sans repli automatique.

Le relief mondial couvre Web Mercator (environ ±85,0511°), à z0–12 puis sur-zoomé. Les datums, résolutions natives et modèles de terrain/surface sont mixtes. Les courbes gardent leurs limites canadiennes et leur provenance MNEMR-30; ce n'est pas un produit d'arpentage. /coverage.json indique la source active. Le même MNE alimente l'API d'altitude. Gardez les attributions de chaque source.

Terrain en 3D

Ajoutez terrain=on pour dessiner n'importe quel style sur un terrain en 3D, les styles plats compris. Le document de style gagne une source raster-dem unmap_terrain et une clé terrain de premier niveau que MapLibre applique au chargement du style; inclinez la carte pour la voir. exaggeration amplifie le relief, de 0.1 à 5 (défaut 1).

GET /styles/winter.json?terrain=on&exaggeration=1.5&key=...
import { createMap } from "@unmap/maps";
 
const map = createMap({ key: "um_live_...", container: "map", style: "winter", terrain: true, exaggeration: 1.5 });
map.setPitch(60);

Le terrain en 3D n'ajoute aucun ombrage à un style qui n'en a pas, et sa source est distincte du unmap_dem de l'ombrage, ce que MapLibre rend mieux qu'une seule source pour les deux. Un terrain autre que on ou off, une exaggeration hors plage, ou une exaggeration sans terrain=on donne un 400. Sans terrain configuré sur la passerelle, la requête donne un 503 plutôt qu'une carte plate. Les tuiles de terrain sont facturées comme toute autre tuile.

Thèmes personnalisés

?theme= transporte un code de thème produit par le créateur de thèmes. Un thème est purement des données : des couleurs, quelques nombres bornés et un nom de style. Il remplace les couleurs qu'aurait utilisées le style, donc il l'emporte sur le style nommé par le chemin.

Les codes existent sous deux formes. Un style, un préréglage nommé ou des couleurs de départ personnalisées tiennent dans un code court u… de quelques caractères ; un thème dont les couleurs ont été retouchées à la main au-delà de cela retombe sur un document ut1., du base64url d'un corps JSON compressé en deflate.

GET /styles/base.json?theme=ut1.eJyrVipTsjLUUcpLzE1VslIqLilKTS1R0lFKSixG4tcCAOvhDGQ&key=...

Les deux formes se passent dans le même paramètre, et les deux arrivent à @unmap/sdk comme l'option theme :

résultat en direct
le code qui l'a produit
import { Unmap } from "@unmap/sdk";

const unmap = new Unmap({
  key: "um_live_...",
  container: "map",
  theme: "u4e",
  center: [-114.0719, 51.0447],
  zoom: 12,
});

?mode= choisit toujours la moitié du thème que vous recevez, et un mode non reconnu retombe sur light. Le terrain et les sprites suivent le style sous-jacent du thème, donc un thème bâti sur outdoor conserve son ombrage.

Un thème peut aussi masquer ou réordonner les sept grands groupes de couches (sol, eau, bâtiments, routes, frontières, bâtiments 3D, étiquettes) pour les deux modes à la fois. C'est le panneau Couches de la carte du créateur ; sur le fil, c'est un seul champ layers fait de booléens et d'une liste ordonnée, et les groupes masqués sont simplement absents du style que vous recevez. Les bâtiments 3D sont le seul groupe désactivé par défaut : une fill-extrusion composée à partir des hauteurs de bâtiments des tuiles, dans la couleur des bâtiments du thème.

Un code invalide est rejeté franchement avec un 400, contrairement à un ?mode= non reconnu :

{
  "error": "invalid theme",
  "code": "invalid_theme",
  "detail": ["code is not valid base64url deflate data"],
}

C'est délibéré. Les thèmes sont assez récents pour n'avoir aucune URL codée en dur à préserver, et un thème ignoré en silence est la pire réponse possible pour quelqu'un qui itère dans le créateur. detail nomme les chemins de champs fautifs lorsque le code se décode mais échoue à la validation.

Un style thématisé porte aussi le style résolu du marqueur et de l'itinéraire dans ses metadata, pour qu'un client ayant déjà chargé le style puisse dessiner ses calques aux couleurs du thème sans décoder le code lui-même :

"metadata": {
  "unmap:theme": {
    "marker": { "color": "#FF3E9A", "scale": 1 },
    "route": { "color": "#FF3E9A", "width": 3, "opacity": 1,
               "casingColor": "#FF3E9A", "casingWidth": 10, "casingOpacity": 0.2 }
  }
}

metadata est absent lorsque vous demandez un style plutôt qu'un thème.

Langue des libellés

Le paramètre ?lang= définit la langue des libellés :

GET /styles/base.json?mode=light&lang=fr&key=...

Sans lang, la passerelle lit Accept-Language, donc une carte intégrée s'affiche dans la langue du lecteur sans que la page hôte ait à le demander. Un tag complet se résout par son sous-tag principal, donc fr-CA vous donne le français. Un code non pris en charge retombe sur l'anglais plutôt que d'émettre en silence un tag que les tuiles ne portent pas. Le jeu Protomaps et les piles de glyphes globales prennent en charge les 41 tags de langue de la liste Protomaps en amont. Le japonais (ja), le coréen (ko), le chinois simplifié (zh-Hans) et traditionnel (zh-Hant) affichent leurs noms natifs. zh-CN choisit le simplifié et zh-TW le traditionnel ; une écriture explicite est prioritaire.

L'exemple de Montréal contient l'anglais et le français : 31 entités diffèrent dans une tuile, dont Nuns' Island et L'Île-des-Sœurs. À l'échelle mondiale, les libellés dépendent des noms réellement présents dans OpenStreetMap; une langue prise en charge ne signifie pas que chaque entité a une traduction.

Les noms autochtones ne sont pas un code lang, et il ne faut pas en demander un. Il n'y a pas de name:iu dans les tuiles. Ces noms voyagent sur l'entité elle-même, donc Iqaluit arrive comme Iqaluit avec ᐃᖃᓗᐃᑦ à côté, et le libellé rend les deux lignes quelle que soit la langue demandée. Ailleurs, le nom syllabique est le principal et l'anglais le secondaire. Rien n'a besoin d'être activé.

Polices et sprites

Les glyphes sont les formes de lettres avec lesquelles MapLibre dessine les étiquettes, et une feuille de sprites est l'image unique qui contient toutes les icônes d'un style. Les URL glyphs et sprite du style pointent elles aussi vers la passerelle, pas vers un hébergeur d'actifs tiers. Vous ne les appellerez normalement pas vous-même, MapLibre les demande automatiquement dès que vous fixez l'URL du style. Les URL générées portent la clé en ?key=. Les appels directs acceptent aussi Authorization: Bearer <key> ou X-API-Key: <key>, comme les tuiles.

GET /glyphs/{version}/{fontstack}/{range}.pbf?key=...
GET /sprite/{version}/{file}?key=...     # file est <feuille>[@2x].(json|png)

Le style donne à MapLibre l'URL du sprite sans extension (/sprite/2/light) et MapLibre ajoute lui-même .json, .png et @2x. Quatre feuilles existent : light, dark, et les désaturées muted-light et muted-dark. Les icônes de POI sont des sprites matriciels colorés par feuille, donc muted, qui est en niveaux de gris jusqu'à ses icônes, a besoin de ses propres feuilles ; tout autre style emprunte la feuille correspondant à son mode, car les icônes varient autrement selon le mode et non selon le style.

Les polices sont les piles Noto Sans, et chacune fusionne plusieurs fontes sources plutôt que de couvrir une seule écriture. Noto Sans Regular contient déjà le syllabaire autochtone canadien unifié, donc ᐃᖃᓗᐃᑦ se rend en texte plutôt qu'en cases vides. Il n'existe pas de famille Noto Sans Canadian Aboriginal distincte à demander; en réclamer une retourne un 404, car rien n'est stocké sous ce nom.

Les glyphes arabes et hébreux sont dans cette même police. MapLibre 6.9 et les versions suivantes les lient et les ordonnent sans plugin de texte de droite à gauche, donc une carte MapLibre standard les dessine à partir de la seule URL de style. Les libellés d'eau, d'océan, d'île et de lac sont en italique pour les noms latins. Pour lang=ar, lang=fa, lang=ur et lang=he, ces couches utilisent Regular, parce que l'italique n'a pas de glyphes arabes ni hébreux et que Regular en a.

Les polices globales incluent le hiragana, le katakana, le hangûl et les idéogrammes CJK, y compris dans les lignes locales et les cartouches routiers. Les variantes JP, KR, SC et TC utilisent les glyphes Noto Sans CJK correspondants. Les caractères CJK ajoutés ont la graisse Regular, même dans les polices Medium et Italic. Les glyphes existants conservent leur graisse. lang=hi, lang=ne et lang=mr gardent la police dévanagari et les noms préformatés disponibles. Le façonnage des écritures complexes reste limité par le moteur de rendu ; une langue prise en charge ne garantit pas une traduction de chaque lieu.

Les chemins /glyphs/ et /sprite/ portent un segment de version d'actif. Il n'adresse rien, l'objet sous-jacent est le même, et il existe uniquement pour qu'une police réécrite obtienne une nouvelle URL, car une réponse réussie est servie immutable pendant un an et le cache est indexé sur le chemin. La version est actuellement 2. Les deux ne sont servis que sous ce segment : /glyphs/{version}/{fontstack}/{range}.pbf et /sprite/{version}/{file}.

Une plage de glyphes ou une feuille de sprites manquante est un 404 en texte brut not found, pas un 500, et cette réponse n'envoie pas l'en-tête de cache d'un an. MapLibre encaisse une lacune de couverture, mais un 5xx ici pourrait faire tomber toute la carte. Une pile de polices, une plage, un nom de sprite ou un segment de version mal formés retournent un 400 en texte brut.

Les glyphes et les sprites sont authentifiés et soumis à la limite de débit comme le reste, mais ils ne sont pas comptabilisés. Un seul chargement de carte tire de nombreuses plages de glyphes, et les compter noierait votre usage réel tout en pénalisant les cartes denses en libellés.

Prochaines étapes