30.10.26
🚀 Migration API ClinicalTrials.gov v2 : pagination & endpoints14 min de lecture2 853 mots

🚀 Migration API ClinicalTrials.gov v2 : pagination & endpoints

Découvrez la migration API ClinicalTrials.gov v2 : pagination, endpoints et remplacement API classique. Paramètres, structure des données et XML transitoire.

migration API ClinicalTrials.govAPI ClinicalTrials.gov v2remplacement API classique ClinicalTrials.govpagination API v2endpoints legacy ClinicalTrials.gov
🚀 Migration API ClinicalTrials.gov v2 : pagination & endpoints

API ClinicalTrials.gov : migrer vers v2 sans casser vos outils

Si votre script interroge encore les anciennes routes de ClinicalTrials.gov, un HTTP 404 n'est pas juste « un incident temporaire ». L'API classique a été retirée le 25 juin 2024 : les endpoints comme /api/query/full_studies et /api/query/study_fields ne répondent plus, et les appels vers classic.clinicaltrials.gov finissent aussi par tomber sur une route indisponible.

Passer à l'API v2, ce n'est pas « remplacer un préfixe par un autre ». Les paramètres de recherche ont bougé, la pagination s'appuie sur un curseur, la forme du JSON est différente (et même certains codes ont été normalisés). Résultat : vous pouvez très bien obtenir un HTTP 200... tout en produisant des données fausses si votre script conserve les anciens chemins de champs ou garde ses anciennes hypothèses de tri.

Ce guide détaille quels endpoints et quels paramètres remplacer, où les parseurs peuvent casser, et comment se positionnent les routes legacy XML. L'objectif : choisir une migration adaptée à votre cas (retour rapide au service ou refonte plus durable vers v2).

Pourquoi l'API classique de ClinicalTrials.gov ne répond-elle plus ?

La National Library of Medicine (NLM) a annoncé le retrait de l'ancien site et de son API, effectif le 25 juin 2024. Depuis cette date, les appels aux routes classiques de requête - notamment /api/query/full_studies et /api/query/study_fields - renvoient une erreur 404. Les routes d'information, comme /api/info/study_fields_list, ont aussi disparu.

Le piège, c'est que l'ancien site redirige certaines pages de recherche vers la nouvelle interface. Mais cette redirection ne garantit pas la compatibilité côté API : une requête programmée vers un ancien endpoint n'est pas automatiquement « rejouée » en v2. Et classic.clinicaltrials.gov ne sauve pas la mise : le chemin est redirigé vers le domaine principal, où les anciennes routes restent inaccessibles.

Comment reconnaître le problème ?

Un script qui fonctionnait avant l'été 2024 peut casser de plusieurs façons : erreur 404, réponse vide interprétée comme « aucune étude », ou arrêt du traitement parce que le parseur n'obtient plus le format attendu.

Le réflexe utile : journaliser le code HTTP et le corps de réponse, au lieu de traiter chaque échec comme si c'était simplement un « résultat de recherche ».

Les vérifications réalisées le 14 octobre 2026 confirment le même comportement pour les anciennes routes (requête et information). Mais le point opérationnel est simple : évitez de construire une nouvelle intégration sur les URL classiques.

Ce qui change réellement pour une intégration

En pratique, le passage Ă  v2 touche trois choses :

  • La requĂŞte : expr devient query.term, et la logique de pagination change (pagination Ă  curseur).
  • La rĂ©ponse : les champs sont imbriquĂ©s dans des modules, et les listes ne sont plus reprĂ©sentĂ©es de la mĂŞme façon.
  • L'interprĂ©tation : l'ordre n'est pas forcĂ©ment celui que vous aviez, et les valeurs d'Ă©numĂ©ration sont gĂ©nĂ©ralement des codes en majuscules.

Bref : un ajustement d'URL ne suffit pas. Pour que l'intégration soit fiable, il faut vérifier à la fois le statut HTTP, la forme de la réponse et le sens métier des valeurs récupérées.

Quel endpoint v2 remplace chaque ancienne route ?

L'API v2 regroupe des usages qui étaient séparés entre full_studies et study_fields. L'endpoint central est /api/v2/studies : il renvoie les fiches complètes par défaut, et vous pouvez limiter les champs via le paramètre fields.

Ancienne route ou fonction Remplacement v2 Alternative legacy
/api/query/full_studies /api/v2/studies /api/legacy/full-studies
/api/query/study_fields /api/v2/studies avec fields /api/legacy/study-fields
/api/query/field_values /api/v2/stats/field/values ou une requĂŞte avec fields Aucune
/api/info/data_vrs et /api/info/api_vrs /api/v2/version Versions dans les réponses XML
/api/info/study_fields_list /api/v2/studies/metadata /api/legacy/study-fields-list
/api/info/search_areas /api/v2/studies/search-areas Aucune
Une étude par identifiant NCT /api/v2/studies/{nctId} /api/legacy/public-xml/{nctId}
Téléchargement global /api/v2/studies/download?format=json.zip /api/legacy/public-xml?format=zip

Pour les valeurs de champs, /api/v2/stats/field/values est utile pour récupérer des valeurs distinctes disponibles dans le registre, dans la limite documentée de 250 valeurs. Les endpoints de métadonnées/valeurs/tailles servent à décrire le modèle ; l'idée est de ne plus dépendre des anciennes routes /api/info/.

Une étude ou un export complet

Pour récupérer une étude précise, utilisez /api/v2/studies/{nctId}. La réponse suit le même schéma que les études dans l'export JSON global. Pour récupérer l'ensemble du registre, /api/v2/studies/download?format=json.zip évite de parcourir tout le monde via pagination.

Le téléchargement complet convient bien pour une copie locale ou un traitement batch, moins pour une application interactive. Au 14 octobre 2026, le registre comptait 606 964 études : attendez-vous à un export volumineux, avec de la place disque et une stratégie de reprise si votre réseau ou votre environnement limite les exécutions.

Remplacer une recherche par champs

Une ancienne requête qui ne demandait que NCTId et BriefTitle peut devenir fields=NCTId,BriefTitle. En v2, toutefois, ces valeurs vivent dans une réponse imbriquée : par exemple, l'identifiant NCT se trouve sous protocolSection.identificationModule.nctId.

C'est important pour les traitements aval : si un export alimente une base relationnelle, un tableau de bord ou un pipeline, vérifiez les colonnes réellement produites après migration. Une requête « valide » ne garantit pas que le schéma attendu par votre application est identique.

Comment migrer les paramètres et la pagination ?

La migration des paramètres paraît simple au début. La pagination, elle, change la logique.

Avant, vous sélectionniez une plage avec min_rnk et max_rnk. En v2, vous paginez avec pageSize et un nextPageToken (tant qu'il reste des résultats). Pour la page suivante, vous repassez ce jeton dans pageToken.

Paramètre classique Équivalent v2 Point à vérifier
expr query.term Les zones de recherche par défaut peuvent différer légèrement.
min_rnk, max_rnk pageSize, pageToken pageSize max : 1 000.
fmt=json ou fmt=csv format=json ou format=csv En v2, pas de XML via le paramètre format.
fields fields En v2, les champs demandés sont imbriqués dans le JSON.
Tri implicite par pertinence sort=@relevance v2 ne trie pas forcément par pertinence par défaut.
cond, term, intr, lead, id query.cond, query.term, query.intr, query.lead, query.id Les filtres sont préfixés par query..

Gérer les pages sans perdre de résultats

Par défaut, la taille de page est de 10, avec un maximum à 1 000. Si vous devez parcourir tous les résultats d'une recherche, continuez tant que la réponse contient nextPageToken. Ne « fabriquez » pas un rang de départ en incrémentant : le curseur doit être réutilisé tel quel, tel que renvoyé par l'API.

Si votre traitement a besoin du total, activez countTotal=true. Cela aide Ă  suivre la progression, mais ne remplace pas le jeton de pagination.

En production, documentez ce que vous logguez : nombre total, nombre de pages traitées, erreurs de requête. Ça permet d'attraper rapidement une collecte interrompue avant de publier des données partielles.

Exemple pratique en Python

Voici un exemple minimal en Python avec requests. Il récupère trois résultats, demande deux champs, puis extrait l'identifiant NCT depuis le nouveau chemin JSON.

import requests

base = "https://clinicaltrials.gov/api/v2/studies"

params = {

"query.term": "heart attack",

"fields": "NCTId,BriefTitle",

"pageSize": 3,

"countTotal": "true",

"sort": "@relevance",

}

response = requests.get(base, params=params, timeout=60)

response.raise_for_status()

data = response.json()

print("Nombre total :", data.get("totalCount"))

for study in data.get("studies", []):

identification = study.get("protocolSection", {}).get(

"identificationModule", {}

)

print(identification.get("nctId"))

next_token = data.get("nextPageToken")

Pour la page suivante, ajoutez pageToken=next_token aux paramètres et relancez. Dans une application réelle, mettez ça dans une boucle qui s'arrête quand le jeton disparaît. Et gardez une vraie gestion des erreurs : un souci réseau ne doit pas être interprété comme une « page vide ».

Vérifier le classement des résultats

Les deux versions peuvent renvoyer le même nombre d'études, mais pas forcément dans le même ordre. L'ancien système triait par pertinence ; v2 ne l'applique pas par défaut. Si l'ordre compte (pour une UI, pour des comparaisons, pour des tests), demandez explicitement sort=@relevance et comparez les premières lignes à un cas de référence.

C'est un test particulièrement utile en migration : une requête peut sembler « correcte » parce que le total correspond, alors que les résultats affichés en premier ont changé. Ne validez pas seulement les volumes : comparez aussi les identifiants, les champs essentiels et le comportement de tri.

Quels changements de données faut-il traiter dans le code ?

Le modèle de données est la source n°1 de régressions.

La documentation NLM décrit des noms de champs plus courts et une organisation en modules. Un identifiant qui était auparavant assez « plat » dans l'ancienne réponse devient désormais accessible via un chemin du type protocolSection.identificationModule.nctId.

Et les noms ne sont pas toujours identiques entre ancien et nouveau. Plutôt que de déduire à partir d'un exemple, vérifiez les métadonnées v2 pour confirmer le nom du champ et son chemin dans le JSON. Si votre parseur transforme le résultat en objets internes, c'est un bon endroit pour isoler cette couche d'adaptation.

Tableaux et valeurs d'énumération

En v2, les listes sont des tableaux simples, sans objets enveloppes supplémentaires. Beaucoup de champs sont au pluriel, comme conditions et phases. Si votre parseur attendait une structure précise (par exemple une imbrication « type XML » une étape plus haut), il peut échouer silencieusement ou ignorer des valeurs.

Côté énumérations, la représentation change aussi : des libellés comme « Recruiting » ou « Phase 2 » deviennent des codes comme RECRUITING et PHASE2. Pour relier libellés historiques et codes v2, utilisez /api/v2/studies/enums, qui fournit notamment legacyValue.

Évitez de faire une conversion « partielle » codée en dur si vos usages couvrent plusieurs statuts, phases ou types d'étude. Construire une table à partir des valeurs exposées par l'API est plus simple à maintenir. Et gardez séparément le libellé affiché (pour l'utilisateur) et le code utilisé pour filtrer (côté logique).

Dates et contenu riche

Les dates sont fournies en ISO 8601, avec une précision variable : année seule, mois, ou date complète (et parfois une heure). Des formes comme « June 2020 » ne correspondent donc plus à la même représentation. Certaines valeurs anciennement « inconnues » sont désormais décrites par des booléens, notamment SubmissionUnreleaseDateUnknown et UnpostedEventDateUnknown.

Ne forcez pas toutes les dates dans un format « jour » si la source ne donne qu'un niveau de granularité plus faible : vous inventeriez une précision. Dans une base ou une interface, conservez la valeur telle qu'elle existe, ou représentez explicitement la granularité disponible.

Le contenu enrichi est rendu en Markdown par défaut. Si un système existant dépend d'un formatage précis, le paramètre markupFormat=legacy peut aider à garder un comportement provisoire. Ça ne dispense pas de valider le rendu : HTML, XML ou texte brut ne traiteront pas forcément la même chaîne de la même façon.

Une stratégie de test raisonnable

Avant de basculer un flux de production, mettez en place un jeu de tests représentatif :

  • une Ă©tude avec plusieurs phases ;
  • une Ă©tude avec des rĂ©sultats ;
  • une Ă©tude avec des dates partielles ;
  • une requĂŞte qui renvoie plusieurs pages.

Comparez les valeurs métier, pas juste la forme du JSON.

À minima, vérifiez :

  • le nombre de rĂ©sultats et les identifiants NCT attendus ;
  • l'accès aux champs imbriquĂ©s et aux listes ;
  • les codes d'Ă©numĂ©ration et leur correspondance avec les libellĂ©s affichĂ©s ;
  • les dates partielles et les cas marquĂ©s comme inconnus ;
  • la pagination jusqu'Ă  ce qu'il n'y ait plus de nextPageToken ;
  • le comportement du tri quand vous attendez un ordre particulier.

Faut-il utiliser v2 ou les endpoints legacy XML ?

Les routes /api/legacy/ sont une passerelle de compatibilité. Elles ne remplacent pas réellement une « nouvelle version pérenne » de l'ancienne API classique : l'objectif est de reproduire au plus près les anciens comportements et de faciliter la transition. Elles peuvent sauver un parseur XML existant le temps de migrer, mais elles ont des limites à intégrer au plan.

Première limite : ces routes renvoient du XML uniquement. Demander fmt=json déclenche une erreur HTTP 400, car le paramètre de format attendu est xml.

Deuxième limite : lorsqu'une recherche utilise expr, seuls les 10 000 premiers résultats peuvent être récupérés.

Enfin : la route legacy study-fields ne fournit pas FlowReasonNumUnits ni OrgStudyIdDomain. La documentation indique que ces champs ne contiennent de toute façon aucune donnée sur les études concernées.

Quand le XML transitoire est-il pertinent ?

Diriger rapidement un ancien client vers /api/legacy/study-fields ou /api/legacy/full-studies peut être logique si vous priorisez la continuité de service, et si votre volume reste dans les limites annoncées.

Ça permet de découpler deux étapes : rétablir l'accès aux données, puis adapter progressivement le parseur vers la structure v2.

En revanche, c'est risqué si vous devez parcourir plus de 10 000 résultats, consommer de nouveaux champs, ou compter sur des évolutions de l'API. Et attention aussi aux versions : les endpoints legacy exposent leur propre version, distincte de celle indiquée par /api/v2/version. Ne supposez pas que la version XML reflète l'état de v2.

Choisir selon le coût de maintenance

Situation Choix pragmatique
Parseur XML ancien, correction urgente Endpoint legacy en transition, avec date de sortie définie
Nouveau développement ou intégration à maintenir API v2 en JSON
Export périodique de tout le registre Téléchargement ZIP v2
Recherche interactive avec résultats paginés /api/v2/studies et gestion de nextPageToken
Besoin de CSV pour un traitement tabulaire API v2 avec format=csv

Le critère décisif n'est pas « JSON vs XML ». C'est le coût total : temps d'adaptation du parseur, risque d'interruption, limites de volume, besoin de nouveaux champs, et capacité à tester correctement. Une passerelle legacy peut réduire le risque immédiat, mais si vous la gardez comme chemin principal pendant des mois, vous prolongez une dépendance à un format de compatibilité.

Conclusion

Migrer l'API ClinicalTrials.gov demande plus qu'un changement d'URL. Il faut remplacer la logique de rang par une pagination à curseur, vérifier le tri, adapter les chemins JSON, et gérer les codes d'énumération ainsi que les dates partielles.

Les routes legacy XML peuvent remettre un traitement en état rapidement, mais leurs limites en font une étape de transition, pas une destination.

Pour avancer sans interrompre vos services, commencez par une requête représentative, comparez les résultats, puis isolez les différences de schéma dans une couche d'adaptation. Ensuite, faites évoluer les traitements page par page, et validez l'exhaustivité avant le basculement. Cette méthode prend un peu plus de temps qu'un remplacement « mécanique », mais elle évite surtout de confondre une réponse valide avec une migration réellement correcte.

Questions frequentes

Non. Les routes classiques ont été retirées le 25 juin 2024 et renvoient des erreurs 404. Le site web redirige certaines pages vers la nouvelle interface, mais cette redirection ne répare pas les appels API. Il faut migrer vers /api/v2/ ou, temporairement, utiliser les endpoints /api/legacy/ compatibles XML.
Utilisez query.term pour reprendre l’expression de recherche. Les paramètres de zones spécialisées suivent le même principe : cond devient query.cond, intr devient query.intr, et ainsi de suite. Vérifiez toutefois les zones de recherche par défaut, qui peuvent différer légèrement de celles de l’ancien système.
Définissez le nombre de résultats avec pageSize, puis utilisez le nextPageToken renvoyé pour demander la page suivante via pageToken. La valeur maximale de pageSize est 1 000. Il ne faut pas traduire l’ancien rang en un simple décalage : v2 utilise une pagination par curseur.
Non. Les endpoints legacy sont réservés au XML. Une demande de format JSON, par exemple avec fmt=json, entraîne une erreur HTTP 400. Ils peuvent dépanner un parseur XML historique, mais pour un nouveau développement ou une migration durable, l’API v2 est le choix adapté.

Articles similaires