République
française
dsfr-data
Documentation — Web Components DSFR pour la dataviz
Composant invisible de connexion aux données. Recupere des données depuis une API REST (URL brute ou via un adapter specialise) et les distribue aux autres composants via le systeme d'événements. Supporte aussi les données JSON inline.
Invisible : Ce composant ne rend rien visuellement. Il agit comme un "pont" entre votre API et les composants de visualisation.
dsfr-data-source se connecte a une API, recupere les données et les
redistribue. En mode adapter, il gere la pagination automatique, les filtres server-side
et la pagination pilotable (server-side).
dsfr-data-query est une couche de transformation client-side : il filtre, groupe,
agrège et trie les données. Il ecoute un dsfr-data-source via l'attribut
source et traite les données cote client.
Pattern recommande : <dsfr-data-source api-type="..."> +
<dsfr-data-query source="..."> pour combiner fetch serveur et
transformation client.
Le composant supporte trois modes :
| Mode | Description |
|---|---|
| URL brute | Appel HTTP generique via l'attribut url. Supporte GET/POST, headers,
params JSON, extraction via transform et pagination manuelle via paginate. |
| Adapter | Active via api-type (sans url). L'adapter gere la construction d'URL,
la pagination automatique, les filtres et le parsing spécifiques au provider
(OpenDataSoft, Tabular, Grist, INSEE Melodi). |
| Inline data | Données JSON passees directement via l'attribut data. Pas de fetch HTTP. |
En mode adapter, l'attribut api-type sélectionne le provider :
| api-type | API | Identifiant requis | Pagination | Max records |
|---|---|---|---|---|
opendatasoft |
OpenDataSoft (v2.1) | dataset-id |
offset, 100/page, max 10 pages | 1 000 (relevable : max-records) |
tabular |
Tabular API (data.gouv.fr) | resource |
page, 200/page, max 125 pages | 25 000 (relevable : max-records) |
grist |
Grist (grist.numerique.gouv.fr, getgrist.com) | base-url |
offset, 100/page, illimitee | Illimite |
insee |
INSEE Melodi (api.insee.fr/melodi) | dataset-id |
page, 1 000/page, max 100 pages | 100 000 |
| Attribut | Type | Format / Valeurs | Description |
|---|---|---|---|
id | String | id="ma-source" | Identifiant unique (requis). Les composants en aval l'utilisent pour s'abonner aux données. |
refresh | Number | Entier en secondes. 0 = off | Rafraichissement automatique en secondes (0 = desactive). |
transform | String | "results", "data.items" | Chemin JSONPath vers le tableau de données dans la réponse. Ex: "results", "data.items". |
headers | String | '{"apikey":"abc123"}' | En-têtes HTTP en JSON. Ex: '{"Authorization": "Bearer xxx"}'. Quand le fournisseur attend sa clé sous un en-tête précis (déclaré par sa configuration), un apikey nu est réécrit automatiquement au bon format (#655) ; détail par fournisseur : table des capacités d'ARCHITECTURE. |
api-key-ref | String | "tmdb" | Référence vers une clé API déclarée dans window.DSFR_DATA_KEYS |
cache-ttl | Number | Entier en secondes. Défaut : 3600 | TTL du cache externe en secondes (0 = desactive). Actif uniquement si la page hote enregistre window.DSFR_DATA_CACHE_PROVIDER (#307) — no-op en embed anonyme. |
| Attribut | Type | Format / Valeurs | Description |
|---|---|---|---|
url | String | URL relative ou absolue | URL de l'API a interroger (mode URL brute). Vide en mode adapter ou en mode data inline. |
method | GET · POST | GET | POST | Méthode HTTP : GET (défaut) ou POST. |
params | String | '{"limit": 100}' | Paramètres de requête en JSON. Mode URL : query string en GET, corps de la requête en POST. **Mode adaptateur** (#726) : les paires sont ajoutées à l'URL construite par l'adaptateur, ce qui sert les paramètres propres à l'API que la bibliothèque ne modélise pas — par exemple params='{"timezone":"Europe/Paris"}' pour lire des dates dans un fuseau donné, sans quitter le mode adaptateur. Les clés que l'adaptateur construit lui-même (il les déclare : clauses, pagination, projection, suffixes d'opérateur) sont réservées : elles sont refusées avec une erreur de configuration plutôt que d'écraser une clause (#1137). Seuls les adaptateurs qui acceptent des paramètres libres les transmettent (en chargement paginé comme en fetch-mode="export") ; les autres les ignorent — voir la table des capacités d'ARCHITECTURE. |
paginate | Boolean | Presence = true | Active la pagination serveur en mode URL : injecte page/page_size dans l'URL et publie la meta. |
page-size | Number | Entier positif. Défaut : 20 | Taille de page pour la pagination serveur (nombre de records par page). |
use-proxy | Boolean | Presence = true | Force le passage par le proxy CORS generique (pour les APIs externes sans CORS) |
proxy-url | String | "" | Domaine du proxy CORS pour CETTE source (#340), prioritaire sur window.DSFR_DATA_PROXY et la config build-time. Sert a la fois la reecriture des hotes connus (ceux que la configuration d'un fournisseur declare sans CORS) et le use-proxy generique. Vide = resolution proxy globale habituelle. Ex: proxy-url="https://mon-proxy.fr". |
| Attribut | Type | Format / Valeurs | Description |
|---|---|---|---|
api-type | String | opendatasoft | tabular | grist | insee | Type d'API : l'identifiant d'un adaptateur du registre (ceux de la bibliothèque, ou un adaptateur ajouté par registerAdapter). Toute autre valeur que generic active le mode adaptateur ; generic avec une url reste en mode URL. |
base-url | String | "https://data.iledefrance.fr" | URL de base de l'API, pour les adaptateurs qui adressent un portail par son URL. |
dataset-id | String | "mon-dataset-2024" | Identifiant du jeu de données, pour les adaptateurs qui désignent un jeu par son identifiant. |
resource | String | "2876a346-d50c-..." (UUID) | Identifiant de la ressource (fichier d'un jeu), pour les adaptateurs qui désignent une ressource. |
where | String | Colon : "champ:op:val"ODS : ODSQL libre | Clause WHERE statique |
select | String | "sum(pop) as total, region" | Clause SELECT, liste séparée par des virgules. Sa grammaire dépend de l'adaptateur (table des capacités d'ARCHITECTURE, ligne « projection select ») : clause complète ou simple liste de noms de colonnes ; un adaptateur sans projection l'ignore. **Clause complète** : select="count(*) as total, region". Une expression (fonction, alias as, *, chemin pointé, opérateur) est transmise telle quelle ; un nom de champ qui n'est pas un identifiant nu (espace, accent, chiffre initial comme 1_uai) est échappé automatiquement (#767). Une virgule à l'intérieur d'une fonction ou d'une chaîne ne sépare pas. Un select fait UNIQUEMENT d'agrégats, sans group-by (select="sum(montant) as total") se charge en une requête d'une ligne, la valeur calculée par le serveur sur tout le jeu (#810) ; si le filtre ne garde aucune ligne, un count vaut 0 et les autres fonctions null. Quand une dsfr-data-query délègue son regroupement à cette source, le select émis est COMPOSÉ depuis l'aggregate de la query (colonnes d'agrégat + colonnes du group-by) : ce select ne l'écrase pas, sinon la colonne d'alias n'existerait pas dans la réponse et le chiffre affiché serait faux (#859). S'il définit une colonne par une expression aliasée (year(date) as annee) que le regroupement vise, la délégation est refusée — avertissement en console, regroupement calculé côté client. **Liste de noms de colonnes** (projection seule, #985) : select="nom, Code sexe", espaces et accents admis — l'API ne rend que ces colonnes, soit dix fois moins d'octets sur un jeu large. Aucune colonne n'est ajoutée d'office : une colonne lue en aval (graphique, liste, facette, filtre client) doit y figurer, et un nom inconnu du jeu fait répondre l'API en erreur. Sans effet quand un group-by ou un aggregate est posé (sur la source ou délégué par une query), si l'API refuse la projection à côté d'un agrégateur. Une expression (fonction, alias, *) est ignorée avec un avertissement : toutes les colonnes sont chargées. |
group-by | String | "champ1, champ2" | Group-by, délégué aux adaptateurs déclarant serverGroupBy. Avec un select en clause complète, un élément peut être une expression aliasée, avec ou sans fonction (year(date) as annee, periode as an), transmise telle quelle — l'alias as y est obligatoire (#641). Même découpe et même échappement que select (#767) : date_format(d, 'yyyy-MM') as m reste d'un seul tenant. |
aggregate | String | "champ:fn" ou "champ:fn:alias" | Agrégation, déléguée aux adaptateurs déclarant serverGroupBy. |
order-by | String | "champ:asc" ou "champ:desc" | Order-by |
limit | Number | Entier positif. 0 = illimite | Limite du nombre de résultats |
max-records | Number | Entier positif. 0 = plafond par défaut de l'adapter | Plafond de lignes du chargement complet en mode adaptateur (#233, #1027), honoré par les adaptateurs qui paginent eux-mêmes leur chargement complet. 0 = plafond par défaut de l'adaptateur (valeurs par adaptateur : table des capacités d'ARCHITECTURE, ligne « plafond fetchAll »). À relever explicitement pour charger un jeu plus long par la pagination — par exemple une carte des ≈ 35 000 communes (max-records="40000") — ou pour les tableaux de bord « un fetch, N agrégations client » : attention au nombre de requêtes en boucle (une par page de l'API) et au poids mémoire. Un limit plus petit reste prioritaire. Quand le plafond coupe le jeu, la source signale la troncature (truncated) et un avertissement console cite max-records. |
server-side | Boolean | Presence = true | Mode pagination serveur (datalist, tableaux). Ce qui est délégué ne change pas avec ce mode : une page porte les mêmes filtres, le même regroupement et les mêmes agrégats qu'un chargement complet — seule la façon dont les lignes arrivent change (#852). Un adaptateur qui ne sait pas déléguer une opération rend les lignes brutes et le signale, et l'aval la calcule côté client. |
max-records
En mode adaptateur, le chargement complet s'arrête à un plafond de sécurité : 1 000 lignes sur
Opendatasoft, 25 000 sur Tabular (125 pages de 200). max-records le relève
explicitement, et vaut pour les deux adaptateurs : Opendatasoft (#233) et Tabular (#1027). Sur
Tabular, une carte de toutes les communes (environ 35 000 lignes) demande
max-records="40000", soit jusqu'à 200 requêtes de 200 lignes : c'est le prix à
peser, en requêtes comme en mémoire. Un limit plus petit reste prioritaire.
<dsfr-data-source id="communes" api-type="tabular" resource="…" max-records="40000"> </dsfr-data-source>
Quand le plafond coupe le jeu, la troncature n'est pas muette : la source la signale
(truncated, lisible dans le volet Diagnostic) et un avertissement console cite
max-records comme moyen de la lever. C'est vrai aussi sur un group-by
délégué, dont l'API ne donne pas le total : une page pleine au plafond avec une page suivante
annoncée suffit à la signaler. Les autres adaptateurs (Grist, INSEE Melodi) ignorent l'attribut.
fetch-mode
En mode adaptateur, la source pagine par tranches de 100 lignes. Pour une page « un fetch, N
agrégations client », c'est autant d'allers-retours ; et sur un group-by à beaucoup
de groupes, le portail ne rend qu'une page de groupes.
fetch-mode="export" passe par l'endpoint d'export du portail, qui rend tout d'un coup,
avec les mêmes clauses (select, where, group-by,
order-by).
| Attribut | Type | Défaut | Description |
|---|---|---|---|
fetch-mode | records · export | records | Stratégie de chargement en mode adaptateur (#689) : records (défaut, comportement historique — pagination par pages) ou export, qui charge tout le jeu en **une seule requête**, ou en quelques plages, sur l'endpoint d'export de l'API. Implémenté par les adaptateurs qui ont un endpoint d'export (table des capacités d'ARCHITECTURE, ligne « chargement en une requête ») ; les autres ignorent l'attribut. Selon l'adaptateur, l'export porte les mêmes clauses (select, where, group-by, order-by) ou ne rend que des **lignes brutes** (#1055) : dans ce dernier cas, avec un where, group-by, aggregate ou order-by délégué (posé sur la source ou transmis par une dsfr-data-query), la source reste sur la pagination, qui les exécute côté serveur, et le dit en console. Un export binaire (colonnes projetées depuis select) charge son lecteur à la demande seulement. Pour une première page rapide sur un petit jeu, la pagination reste plus vive ; l'export l'emporte au-delà de 1 000 à 2 000 lignes. À activer pour une page « un fetch, N agrégations client », un jeu de plus de 1 000 lignes, ou un group-by à beaucoup de groupes : l'API les rend tous d'un coup au lieu d'une page. À ne pas activer avec server-side (pagination page par page), qui reste sur l'endpoint paginé et signale la contradiction dans la console. En mode export le total serveur est inconnu : la troncature est détectée en demandant une ligne de plus que le plafond max-records, qui borne aussi les lignes lues. Si l'API n'expose pas d'endpoint d'export, la source retombe une fois sur le chargement paginé, avec un avertissement en console. |
<dsfr-data-source id="src" api-type="opendatasoft" base-url="https://data.economie.gouv.fr" dataset-id="mon-jeu" fetch-mode="export" max-records="20000"> </dsfr-data-source>
Implémenté par les adaptateurs OpenDataSoft et Tabular ; les autres l'ignorent, et une source dont le
portail n'expose pas d'endpoint d'export retombe une fois sur le chargement paginé, avec un
avertissement console. À ne pas combiner avec server-side, qui pagine page par page
et reste sur l'endpoint paginé : la contradiction est signalée dans la console. Sur OpenDataSoft, le
total serveur est inconnu en mode export, donc la troncature est détectée en demandant une ligne de
plus que le plafond max-records — pensez à relever ce plafond en même temps.
Sur une source api-type="tabular", fetch-mode="export" lit l'export
Parquet que data.gouv publie pour chaque ressource, par plages, en ne lisant que les
colonnes du select. Mesuré sur le jeu IRVE (223 174 lignes) : le jeu entier en 0,66 s et
17 requêtes, là où la pagination met 10,8 s et 125 requêtes pour 25 000 lignes. Le lecteur
(≈ 22 Ko gzip) n'est chargé qu'à ce moment-là : il n'alourdit pas les autres pages.
where, un group-by, un
aggregate ou un order-by délégué — posé sur la source ou transmis par une
dsfr-data-query —, la source reste sur la pagination, qui les exécute côté serveur, et
le dit une fois en console. Pour « un fetch, N agrégations », posez les calculs sur des
dsfr-data-query qui partagent la source : ils restent alors côté client.
max-records (25 000 par défaut, comme la pagination) borne les lignes
lues. Le fichier annonce son nombre de lignes : le total est connu, et une troncature se dit
comme en pagination.
AAAA-MM-JJ, colonne __id quand aucun select n'est posé. Une
ressource sans export retombe sur la pagination, avec un avertissement.
<dsfr-data-source id="bornes" api-type="tabular" resource="eb76d20a-8501-400e-b336-d85724de5435" select="nom_station, consolidated_latitude, consolidated_longitude" fetch-mode="export" max-records="250000"> </dsfr-data-source>
| Attribut | Type | Format / Valeurs | Description |
|---|---|---|---|
data | String | JSON valide (tableau ou objet) | Données JSON inline (pas de fetch) |
Sans précaution, une source interroge son API dès le montage et rapatrie le jeu entier — une
requête coûteuse dont personne ne regarde le résultat sur une page d'exploration, où l'utilisateur
va de toute façon commencer par choisir une commune, une année, un thème.
require-where retarde le premier appel jusqu'à ce filtre.
| Attribut | Type | Défaut | Description |
|---|---|---|---|
require-where | Boolean | false | Ne rien charger tant qu'aucun filtre n'a été reçu (#690). Pensé pour les pages d'exploration : sans cet attribut, une source interroge l'API dès le montage et rapatrie le jeu entier — une requête coûteuse dont personne ne regarde le résultat. Avec lui, la source reste en attente, émet dsfr-data-idle et ne part chercher les données qu'au premier filtre. Ce qui compte comme filtre : les clauses reçues par commande — facettes, recherche, dsfr-data-context, délégation d'un dsfr-data-query (son where, avec ou sans group-by, quand elle est seule lectrice de la chaîne — #856). Le where STATIQUE de la source ne compte PAS : il fait partie de la définition du jeu, pas du geste de l'utilisateur ; le contraire rendrait l'attribut sans effet sur toute source qui restreint déjà son périmètre. Quand le dernier filtre est retiré, la source repasse en attente : jamais de requête « tout » implicite. Sans effet en mode données inline (data), qui ne fait aucune requête. |
<dsfr-data-source id="src" api-type="opendatasoft" require-where base-url="https://data.economie.gouv.fr" dataset-id="equipements"> </dsfr-data-source> <dsfr-data-facets source="src" fields="commune"></dsfr-data-facets> <dsfr-data-list source="src" idle-message="Choisissez une commune pour afficher ses équipements"> </dsfr-data-list>
Ce qui compte comme filtre : les clauses reçues par commande — facettes,
recherche, dsfr-data-context, délégation d'un
dsfr-data-query. Le where STATIQUE de la source ne
compte pas : il fait partie de la définition du jeu, pas du geste de l'utilisateur — le contraire
rendrait l'attribut sans effet sur toute source qui restreint déjà son périmètre. Quand le dernier
filtre est retiré, la source repasse en attente : jamais de requête « tout » implicite. Sans effet
en mode data inline, qui ne fait aucune requête.
Pendant l'attente, la source publie dsfr-data-idle plutôt que des données vides. Les
afficheurs en aval (list,
display, kpi,
chart, podium,
search, a11y) rendent alors
leur idle-message — « Choisissez un filtre pour afficher les données » par défaut —
et non « aucune donnée », qui annoncerait une requête revenue vide. Un pendant purement client
existe sur dsfr-data-query.
Une page à onglets déclare ses sources pour tous les panneaux ; cinq sur six sont
fermés à l'arrivée, et pourtant toutes les requêtes partent au chargement. Avec
lazy, la première requête attend qu'un consommateur de la source entre dans une marge
de 200 px autour du viewport. Un panneau fermé est en display:none : il n'a pas de
boîte, il n'intersecte jamais, et l'observateur se déclenche à l'ouverture de l'onglet.
| Attribut | Type | Défaut | Description |
|---|---|---|---|
lazy | Boolean | false | Ne rien charger tant que personne ne regarde (#931, AM-083). Une page à onglets déclare ses sources pour TOUS les panneaux ; cinq sur six sont fermés à l'arrivée, et pourtant toutes les requêtes partent au chargement. Avec lazy, la première requête attend qu'un consommateur de cette source entre dans une marge de 200 px autour du viewport (IntersectionObserver, la même marge que dsfr-data-map et que le lazy de dsfr-data-repeat, #891). Un panneau d'onglet fermé est en display:none : il n'a pas de boîte, il n'intersecte donc jamais, et l'observateur se déclenche à l'ouverture de l'onglet. **Ce qui est observé** : les FEUILLES de la chaîne aval (chart, list, kpi, display, podium, a11y, repeat ; pour une couche de carte, la carte qui la porte), suivies à travers les transformateurs — un dsfr-data-query est un tuyau déclaré en haut de page, l'observer reviendrait à ne rien différer. lazy-target remplace cette détection par un sélecteur explicite. **Opt-in strict** : sans l'attribut, la source part au chargement, exactement comme avant. **Dégradations, toutes du côté « on charge » :** sans IntersectionObserver, la source part immédiatement ; si la page ne déclare AUCUN consommateur (ou si lazy-target ne désigne rien), la source part immédiatement et le dit en console — une source qui ne chargerait jamais serait pire que le trafic qu'on cherche à éviter. **Ce que lazy ne promet pas** : un IntersectionObserver n'est pas continu. Il échantillonne aux temps de rendu ; un défilement par crans rapides (barre de défilement jetée, scrollIntoView enchaînés) peut traverser un consommateur sans jamais le rapporter comme visible — la source reste alors en attente jusqu'au prochain passage. C'est le comportement du navigateur, pas un bug de la bibliothèque. Se cumule avec require-where : les deux portes doivent s'ouvrir, et require-where est évalué en premier (c'est son message d'attente que l'utilisateur doit lire). Sans effet en mode données inline (data), qui ne fait aucune requête. |
lazy-target | String | "" | Sélecteur CSS de l'élément dont la visibilité déclenche le chargement, à la place des consommateurs détectés (#931). Sans effet sans lazy. lazy lazy-target="#panneau-2" : la source part quand le panneau entre dans la marge de 200 px. À utiliser quand la détection automatique ne peut pas voir le bon élément — un consommateur créé en JavaScript, une carte dont on préfère observer la section entière, ou plusieurs blocs qu'on veut traiter comme un seul (le sélecteur peut désigner plusieurs éléments : le PREMIER vu ouvre la porte). Sélecteur invalide, ou qui ne désigne aucun élément : la source part immédiatement, avec un message en console. Rien de silencieux. |
<!-- Les sources de l'onglet 2 ne partent qu'à son ouverture --> <dsfr-data-source id="s-clubs" api-type="opendatasoft" lazy base-url="https://data.sports.gouv.fr" dataset-id="clubs"> </dsfr-data-source> <div class="fr-tabs__panel" id="panneau-2"> <dsfr-data-chart source="s-clubs" type="bar" label-field="dep" value-field="n"></dsfr-data-chart> </div> <!-- Cible explicite, quand la détection automatique ne voit pas le bon élément --> <dsfr-data-source id="s-carte" api-type="opendatasoft" lazy lazy-target="#panneau-3" base-url="https://data.sports.gouv.fr" dataset-id="equipements"> </dsfr-data-source>
Ce qui est observé : les feuilles de la chaîne aval (chart, list, kpi,
display, podium, a11y, repeat ; pour une couche de carte, la carte qui la porte), suivies à travers
les transformateurs. Un dsfr-data-query est un tuyau déclaré en haut de page :
l'observer reviendrait à ne rien différer.
Toutes les dégradations vont du côté « on charge » : sans
IntersectionObserver, ou si la page ne déclare aucun consommateur (ou si
lazy-target ne désigne rien), la source part immédiatement et le dit en console. Une
source qui ne chargerait jamais serait pire que le trafic qu'on cherche à éviter.
Ce que lazy ne promet pas : un IntersectionObserver
n'est pas continu. Il échantillonne aux temps de rendu ; un défilement par crans rapides peut
traverser un consommateur sans jamais le rapporter comme visible — la source reste alors en
attente jusqu'au prochain passage. C'est le comportement du navigateur, pas un bug.
Se cumule avec require-where : les deux portes doivent s'ouvrir, et
require-where est évalué en premier — c'est son message d'attente que l'utilisateur
doit lire. Pendant l'attente de lazy, la source publie dsfr-data-idle
avec la raison lazy, que le volet Diagnostic distingue de l'attente d'un filtre.
L'attribut where definit un filtre permanent sur la source.
En mode Tabular / Grist, format colon champ:operateur:valeur :
where="population:gt:5000" where="population:gt:5000, region:in:IDF|OCC|BRE" where="email:isnull"
En mode OpenDataSoft, syntaxe ODSQL libre :
where="population > 5000 AND status = 'active'"
Les composants en aval (dsfr-data-facets, dsfr-data-search) peuvent ajouter
des filtres dynamiques via le systeme de commandes. Ces filtres sont fusionnes
avec le where statique a chaque requête.
Chaque composant envoie un overlay identifie par une clé unique (whereKey).
Les overlays sont combines en ET logique. La méthode getEffectiveWhere()
retourne la clause WHERE fusionnee.
<!-- WHERE statique + overlays dynamiques des facettes et recherche --> <dsfr-data-source id="src" api-type="opendatasoft" dataset-id="rappelconso-v2-gtin-trie" base-url="https://data.economie.gouv.fr" where="categorie_produit = 'Alimentation'" server-side page-size="20"> </dsfr-data-source> <!-- La recherche ajoute un overlay WHERE via server-search --> <dsfr-data-search id="search" source="src" server-search> </dsfr-data-search> <!-- Les facettes ajoutent des overlays WHERE --> <dsfr-data-facets id="facets" source="src" fields="categorie_produit, marque_produit" server-facets> </dsfr-data-facets>
Avec server-side, dsfr-data-source charge une seule page
a la fois et ecoute les commandes des composants en aval pour naviguer entre les pages.
Cela permet d'afficher des datasets de milliers d'enregistrements sans tout charger en memoire.
Le composant reagit a trois types de commandes :
| Commande | Source | Effet |
|---|---|---|
{ page } | dsfr-data-list | Change la page courante et re-fetche |
{ where, whereKey } | dsfr-data-facets, dsfr-data-search | Ajoute/supprime un overlay WHERE et reset a la page 1 |
{ orderBy } | dsfr-data-list | Change le tri et re-fetche |
<dsfr-data-source id="prix-ct" url="https://data.economie.gouv.fr/api/explore/v2.1/catalog/datasets/prix-controle-technique/records" transform="results" ></dsfr-data-source>
<dsfr-data-source id="api-privee" url="https://mon-api.gouv.fr/data" method="POST" headers='{"Authorization": "Bearer TOKEN"}' params='{"limit": 100, "filters": {"annee": 2024}}' transform="data.items" refresh="60" ></dsfr-data-source>
Avec paginate, chaque changement de page dans un dsfr-data-list
en aval declenche un nouvel appel API avec les paramètres de pagination.
<dsfr-data-source id="browse" api-type="opendatasoft" dataset-id="rappelconso-v2-gtin-trie" base-url="https://data.economie.gouv.fr" server-side paginate page-size="20" ></dsfr-data-source> <dsfr-data-list source="browse" columns="modeles_ou_references:Produit, categorie_produit:Catégorie, marque_produit:Marque" pagination="20"> </dsfr-data-list>
Auto-extraction : en mode paginate, pas besoin de transform="data".
Les données sont automatiquement extraites depuis json.data et les metadonnees de pagination
(json.meta) sont stockees pour calculer le nombre total de pages.
L'attribut use-proxy force le passage par le proxy CORS generique.
Utile quand l'API cible ne renvoie pas les headers CORS necessaires.
<dsfr-data-source id="ghibli-films" url="https://ghibliapi.vercel.app/films" use-proxy ></dsfr-data-source>
Fonctionnement : en dev, la requête est routee via le middleware Vite
/cors-proxy. En production, elle passe par l'endpoint equivalent sur le serveur proxy
(<votre-proxy>/cors-proxy).
L'URL cible est transmise dans le header X-Target-URL.
L'adapter gere automatiquement la construction d'URL, la pagination et le parsing. Pagination automatique (toutes les pages en une seule requête) jusqu'a 1 000 records.
<dsfr-data-source id="elus" api-type="opendatasoft" base-url="https://data.iledefrance.fr" dataset-id="elus-regionaux" where="sexe = 'F'" ></dsfr-data-source> <dsfr-data-query id="stats" source="elus" group-by="groupe_politique" aggregate="nom:count:nb" order-by="nb:desc"> </dsfr-data-query> <dsfr-data-chart source="stats" type="bar" label-field="groupe_politique" value-field="nb"> </dsfr-data-chart>
L'adapter ODS gere la pagination, le tri serveur, la recherche full-text et les facettes. Ici un simple datalist pagine.
<dsfr-data-source id="src-ods" api-type="opendatasoft" dataset-id="rappelconso-v2-gtin-trie" base-url="https://data.economie.gouv.fr" server-side page-size="20" ></dsfr-data-source> <dsfr-data-list source="src-ods" columns="modeles_ou_references:Produit, categorie_produit:Catégorie, marque_produit:Marque, date_publication:Date" server-sort pagination="20"> </dsfr-data-list>
L'adapter Grist se connecte aux instances Grist (grist.numerique.gouv.fr ou getgrist.com). Il détecté automatiquement si la requête necessite le mode SQL (groupement, agrégation, operateurs avances) ou le mode Records standard.
<dsfr-data-source id="grist-data" api-type="grist" base-url="https://grist.numerique.gouv.fr/api/docs/DOC_ID/tables/TABLE_ID/records" headers='{"Authorization": "Bearer TOKEN"}' ></dsfr-data-source> <dsfr-data-chart source="grist-data" type="bar" label-field="nom" value-field="valeur"> </dsfr-data-chart>
Aplatissement automatique : l'adapter Grist aplatit lui-même la structure
records[].fields de la réponse — aucun dsfr-data-normalize n'est
nécessaire en mode adapter. Le flatten de normalize ne sert que si vous appelez
l'API Grist en mode URL brute (attribut url sans api-type),
où la réponse arrive telle quelle.
Avec server-side, la source charge une page a la fois.
Le dsfr-data-list en aval pilote la navigation entre les pages.
<dsfr-data-source id="srv" api-type="opendatasoft" dataset-id="rappelconso-v2-gtin-trie" base-url="https://data.economie.gouv.fr" server-side page-size="20" ></dsfr-data-source> <dsfr-data-list source="srv" columns="modeles_ou_references:Produit, categorie_produit:Catégorie, marque_produit:Marque" server-sort pagination="20"> </dsfr-data-list>
L'attribut data permet de passer des données JSON directement,
sans aucun appel HTTP. Utile pour les exemples, prototypes ou données statiques.
<dsfr-data-source id="inline" data='[{"nom":"Paris","pop":2161000},{"nom":"Lyon","pop":516092},{"nom":"Marseille","pop":870731}]' ></dsfr-data-source> <dsfr-data-chart source="inline" type="bar" label-field="nom" value-field="pop"> </dsfr-data-chart>
api-key-ref)
Au lieu d'ecrire les tokens directement dans les attributs HTML, declarez-les une seule fois
dans un registre global window.DSFR_DATA_KEYS, puis referencez-les par nom
avec api-key-ref. La clé est injectee comme header Authorization.
<script> window.DSFR_DATA_KEYS = { tmdb: 'Bearer eyJhbGciOiJIUzI1NiJ9...', monapi: 'Token abc123' }; </script> <dsfr-data-source id="films" url="https://api.themoviedb.org/3/movie/popular" api-key-ref="tmdb" transform="results" ></dsfr-data-source>
Comportement : si api-key-ref est défini et que la clé existe
dans window.DSFR_DATA_KEYS, elle est injectee en header Authorization
a chaque requête. Si la clé n'est pas trouvee, un avertissement est emis dans la console et
la requête est envoyee sans authentification. Fonctionne avec les deux modes (URL brute et adapter).
Securite : les clés restent lisibles par tout script sur la page
(même modele de securite que l'attribut headers). Cette fonctionnalite est une
commodite pour separer la declaration des clés du markup, pas un mecanisme de protection.
Pour les clés sensibles, utilisez un proxy serveur.
L'attribut refresh re-execute la requête a intervalles reguliers (en secondes).
Fonctionne dans les deux modes (URL brute et adapter).
<dsfr-data-source id="live" api-type="opendatasoft" base-url="https://data.opendatasoft.com" dataset-id="mon-dataset" refresh="30" ></dsfr-data-source>
Le composant emet des événements personnalises via le systeme data-bridge :
dsfr-data-loaded : Données chargees avec succes (detail : tableau de records)dsfr-data-loading : Chargement en coursdsfr-data-error : Erreur de chargement (detail : objet Error)cache-fallback : Les données proviennent du cache serveur suite a une erreur API (mode DB uniquement)| Méthode | Retour | Description |
|---|---|---|
reload() | void | Force le rechargement des données |
getData() | unknown | Retourne les données actuelles |
isLoading() | Boolean | Indique si un chargement est en cours |
getError() | Error | null | Retourne l'erreur eventuelle |
getAdapter() | ApiAdapter | null | Retourne l'adapter actif (mode adapter uniquement, null en mode URL brute) |
getEffectiveWhere(excludeKey?) | String | Retourne la clause WHERE fusionnee (statique + tous les overlays dynamiques).
Le paramètre excludeKey permet d'exclure un overlay spécifique (utilise par les facettes). |
Choisir le bon mode : Utilisez le mode URL brute pour vous connecter a n'importe quelle API REST. Utilisez le mode adapter pour les APIs connues (ODS, Tabular, Grist) afin de beneficier de la pagination automatique, des filtres server-side et de la construction d'URL geree.
server-side vs pagination automatique : Sans server-side, l'adapter
charge toutes les données (multi-pages) en une seule operation. Avec server-side,
il charge une seule page et attend les commandes des composants en aval. Utilisez
server-side pour les grands datasets avec un dsfr-data-list pagine.
Pipeline de données : dsfr-data-source s'integre dans un pipeline :
dsfr-data-source → dsfr-data-normalize →
dsfr-data-query / dsfr-data-search / dsfr-data-facets →
composants de visualisation.
Securite : les headers, tokens et clés dans window.DSFR_DATA_KEYS
sont visibles dans le code source HTML. Ne les utilisez que pour des clés a acces restreint (lecture seule)
ou dans des contextes proteges (intranet, applications internes).
Pour une separation propre entre markup et clés, utilisez api-key-ref.