ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Ressources dépendantes dans dlt

Comment dlt permet à une ressource d'utiliser la sortie d'une autre pour configurer son endpoint — la syntaxe de template de chemin pour le parcours multi-étape d'une API.

Planté
dltdata engineeringetl

De nombreux pipelines API nécessitent un parcours multi-étape : récupérer une liste d’entités, puis pour chaque entité récupérer ses enregistrements liés. dlt offre un support de première classe pour ce pattern via les ressources dépendantes.

Le pattern

Une ressource dépendante utilise les données retournées par une ressource parente pour construire sa propre URL d’endpoint. Dans la configuration REST API Source, cela s’exprime avec un template de chemin :

"resources": [
{
"name": "pokeapi_repos",
"endpoint": {
"path": "orgs/PokeAPI/repos",
},
},
{
"name": "pokeapi_repos_commits",
"endpoint": {
"path": "repos/PokeAPI/{resources.pokeapi_repos.name}/commits",
},
},
],

La référence template {resources.pokeapi_repos.name} dans le chemin de la deuxième ressource récupère le champ name de chaque ligne produite par la ressource pokeapi_repos. Pour chaque dépôt retourné par le premier endpoint, dlt effectue un appel API séparé vers l’endpoint des commits avec le nom du dépôt substitué.

Si pokeapi_repos retourne 30 dépôts, dlt effectue 30 appels vers l’endpoint des commits — un par dépôt. Les lignes résultantes de l’ensemble des 30 appels atterrissent dans la table pokeapi_repos_commits.

La syntaxe de template

Le pattern est {resources.<nom_de_ressource_parente>.<nom_de_champ>}.

  • <nom_de_ressource_parente> doit correspondre exactement au champ name de la ressource parente.
  • <nom_de_champ> est n’importe quel champ retourné dans la réponse de la ressource parente.

Pour les champs imbriqués, utilisez la notation pointée : {resources.parent.owner.login} accèderait au champ login à l’intérieur de l’objet owner de la réponse parente.

Pourquoi cela importe pour la qualité des données

Sans ressources dépendantes, vous auriez deux options : récupérer uniquement la liste parente (en perdant les données de détail), ou écrire une boucle Python qui appelle manuellement l’endpoint enfant pour chaque parent et accumule les résultats. L’approche de la boucle manuelle fonctionne, mais elle renonce à la pagination automatique, l’inférence de schéma et le chargement incrémental de dlt pour la ressource enfant.

Avec les ressources dépendantes, l’endpoint enfant bénéficie du même traitement que le parent : la pagination est gérée automatiquement, le schéma est inféré, et le chargement incrémental peut être configuré indépendamment.

Combinaison avec le chargement incrémental

Les ressources dépendantes et le chargement incrémental se composent proprement. Vous pouvez configurer la ressource enfant pour suivre son propre curseur indépendamment du parent :

{
"name": "pokeapi_repos_commits",
"endpoint": {
"path": "/repos/PokeAPI/{resources.pokeapi_repos.name}/commits",
"params": {
"since": {
"type": "incremental",
"cursor_path": "commit.author.date",
"initial_value": "2024-01-01T00:00:00Z"
}
}
},
},

Ici l’API GitHub accepte un paramètre since pour filtrer les commits par date. dlt suit la valeur maximale de commit.author.date observée dans tous les dépôts lors de l’exécution précédente, et la passe en paramètre since à l’exécution suivante. Cela signifie que le pipeline ne récupère que les commits plus récents que sa dernière exécution réussie — pour chaque dépôt, et non uniquement le premier.

Un point à noter : l’état du curseur est partagé entre toutes les invocations de la ressource enfant. Si vous avez 30 dépôts et que chacun a des commits sur des plages de dates différentes, dlt suit une date maximale unique pour tous. C’est le comportement correct — vous voulez le point de départ le plus sûr — mais cela signifie que le curseur reflète le commit le plus récent vu globalement, et non par dépôt.

Considérations de mise à l’échelle

Les ressources dépendantes multiplient vos appels API. Une ressource parente avec 100 enregistrements signifie 100 appels vers l’endpoint enfant, chacun potentiellement paginé sur plusieurs pages. C’est généralement acceptable, mais cela a des implications :

Limites de débit — Les APIs limitent couramment le débit par fenêtre de temps. 100 enregistrements parents × 10 pages par enfant = 1 000 appels API. Anticipez cela quand vous décidez d’utiliser le chargement incrémental sur le parent pour réduire le fan-out.

Durée du pipeline — Les appels se produisent séquentiellement par défaut. Les requêtes enfants longues (APIs avec des temps de réponse lents) multiplient le temps total du pipeline proportionnellement au nombre d’enregistrements parents.

Tokens API — Les limites de débit sur l’API publique de GitHub sont de 5 000 requêtes/heure pour les requêtes authentifiées. Un pipeline avec 100 dépôts et 10 pages de commits chacun approche cette limite si exécuté fréquemment.

Configurer l’authentification (voir Patterns d’authentification dlt) est particulièrement important pour les pipelines à ressources dépendantes en raison de ce volume d’appels. Les limites de débit non authentifiées sont généralement bien inférieures.

Quand utiliser les ressources dépendantes vs. RESTClient

La syntaxe de template de chemin fonctionne dans la configuration déclarative REST API Source. Si vous utilisez RESTClient directement (le chemin impératif), vous implémentez le même pattern comme une boucle Python explicite :

@dlt.resource
def repos():
for page in client.paginate("orgs/PokeAPI/repos"):
yield page
@dlt.transformer(data_from=repos)
def commits(repo):
for page in client.paginate(f"repos/PokeAPI/{repo['name']}/commits"):
yield page

Le décorateur @dlt.transformer est l’équivalent RESTClient des ressources dépendantes — il consomme une ressource parente et produit des enregistrements enfants. Le template de chemin basé sur la configuration dans REST API Source est du sucre syntaxique pour ce même pattern, et il est plus simple à écrire quand l’API suit les conventions standard.

Pour la plupart des parcours API multi-étapes, la syntaxe de template de chemin de REST API Source est le bon choix. Passez au pattern transformer de RESTClient quand vous avez besoin d’une logique conditionnelle dans la ressource enfant, d’une construction d’endpoint dynamique allant au-delà de la simple interpolation de champ, ou d’une gestion des erreurs par enregistrement parent.

Voir Configuration dlt REST API Source pour l’image complète de la façon dont les ressources dépendantes s’intègrent dans la configuration REST API Source plus large.