L'API ChatGPT évolue vite : contrats qui changent, facturation par jeton même sur des tests ratés, streaming SSE différent du mode non-streaming, appels d'outils à valider, limites de débit visibles trop tard en production. Si vous testez tout dans un REPL Python ou avec des boucles curl, vous perdez du temps, de l'argent et de la visibilité.
Ce guide montre comment tester l'API ChatGPT dans Apidog : authentification, première complétion, streaming SSE, appel de fonction, erreurs, limites de débit, mocks frontend et scénario CI. À la fin, vous aurez un projet Apidog réutilisable pour détecter les dérives de contrat OpenAI avant la production.
En bref
- Configurez
https://api.openai.com/v1comme URL de base dans un environnement Apidog. - Stockez
OPENAI_API_KEYcomme variable secrète. - Appliquez l'authentification Bearer au niveau du dossier.
- Créez une requête
POST /chat/completionsréutilisable pour vos modèles. - Testez explicitement le streaming SSE avec
stream: true. - Validez les
tool_callsretournés par le modèle. - Simulez ChatGPT avec Smart Mock pour débloquer le frontend.
- Enregistrez les requêtes critiques dans un scénario de test CI avec assertions.
Pourquoi tester l'API ChatGPT ?
L'API OpenAI semble stable, mais plusieurs comportements ont changé ou coexistent encore :
-
function_callettool_calls - Mode strict pour les schémas d'outils
- Modèles de raisonnement (
o1,o3) qui rejettent certains paramètres commetemperatureettop_p response_format: { type: "json_schema" }- Streaming des appels d'outils avec deltas à assembler
- Nouveau point de terminaison
/v1/responses, qui chevauche/v1/chat/completions
Sans couche de test, une simple modification de prompt peut casser le code aval sans erreur immédiate. Une collection Apidog vous donne un contrat exécutable : même requête, mêmes assertions, échec visible si la forme de réponse change.
Étape 1 : créer l'environnement OpenAI dans Apidog
Dans Apidog, créez un nouveau projet, puis ajoutez un environnement appelé OpenAI Prod.
| Variable | Valeur |
|---|---|
baseUrl |
https://api.openai.com/v1 |
OPENAI_API_KEY |
sk-proj-... à stocker comme Secret |
defaultModel |
gpt-5.5 |
Marquez OPENAI_API_KEY comme secret. Elle sera masquée dans les espaces partagés et ne sera pas écrite dans les exports. Chaque membre de l'équipe pourra fournir sa propre clé sans modifier la collection.
Étape 2 : configurer l'authentification Bearer
Créez un dossier ChatGPT.
Dans les paramètres du dossier :
- Ouvrez l'onglet Auth.
- Choisissez Bearer Token.
- Utilisez cette valeur :
{{OPENAI_API_KEY}}
Toutes les requêtes du dossier héritent automatiquement de l'en-tête :
Authorization: Bearer {{OPENAI_API_KEY}}
Résultat : plus besoin de copier la clé dans chaque requête, et la rotation de clé se fait en un seul endroit.
Étape 3 : créer une première requête de complétion
Dans le dossier ChatGPT, créez une requête :
- Méthode :
POST - URL :
{{baseUrl}}/chat/completions - Nom :
chat-completion-basic - Body : JSON
{
"model": "{{defaultModel}}",
"messages": [
{
"role": "system",
"content": "You are a senior backend engineer. Answer in under 100 words."
},
{
"role": "user",
"content": "What's the difference between idempotent and safe HTTP methods?"
}
],
"temperature": 0.2
}
Envoyez la requête.
Vous devez obtenir :
- un statut
200 - une réponse dans
choices[0].message.content - un bloc
usageavec les compteurs de jetons
Exemple de vérifications utiles :
pm.test("Status is 200", () => {
pm.response.to.have.status(200);
});
pm.test("Response has content", () => {
const body = pm.response.json();
pm.expect(body.choices[0].message.content).to.be.a("string");
});
pm.test("Token usage is present", () => {
const body = pm.response.json();
pm.expect(body.usage.total_tokens).to.be.greaterThan(0);
});
Si vous obtenez 401, vérifiez que l'environnement OpenAI Prod est sélectionné et que la clé est bien renseignée.
Si vous obtenez 429, vous avez probablement atteint une limite de débit.
Étape 4 : tester le streaming SSE
Le streaming ChatGPT utilise text/event-stream. La réponse n'est pas un JSON unique : elle arrive sous forme de lignes data: {...} contenant des deltas partiels.
Dupliquez chat-completion-basic, renommez la copie en chat-completion-stream, puis utilisez ce body :
{
"model": "{{defaultModel}}",
"stream": true,
"messages": [
{
"role": "user",
"content": "Stream the first 100 prime numbers, comma-separated."
}
]
}
Envoyez la requête.
Dans Apidog, le panneau de réponse affiche les fragments SSE au fur et à mesure. C'est utile pour déboguer :
- les deltas incomplets
- les chunks malformés
- le terminateur manquant
- les appels d'outils streamés morceau par morceau
Points à vérifier :
- La dernière trame doit être :
data: [DONE]
- Si votre client tente de parser
[DONE]comme JSON, il échouera. - Le champ
usagen'est pas présent par défaut en streaming. - Pour inclure l'utilisation des jetons, ajoutez :
"stream_options": {
"include_usage": true
}
Body complet :
{
"model": "{{defaultModel}}",
"stream": true,
"stream_options": {
"include_usage": true
},
"messages": [
{
"role": "user",
"content": "Stream the first 100 prime numbers, comma-separated."
}
]
}
Pour les appels d'outils en streaming, testez aussi l'assemblage des champs :
indexidfunction.namefunction.arguments
Les arguments peuvent arriver caractère par caractère. Votre client doit les concaténer avant de parser le JSON.
Étape 5 : tester les appels de fonction et les outils
Les appels d'outils cassent souvent silencieusement après une modification de prompt. Le modèle retourne un tableau tool_calls, et votre code doit vérifier que les arguments correspondent au schéma attendu.
Créez une requête chat-completion-tools :
{
"model": "{{defaultModel}}",
"messages": [
{
"role": "user",
"content": "What is the weather in Singapore right now?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"unit": {
"type": "string",
"enum": ["c", "f"]
}
},
"required": ["city"]
},
"strict": true
}
}
],
"tool_choice": "auto"
}
Une réponse exploitable doit contenir :
choices[0].message.tool_calls[0].function.name === "get_weather"
Et function.arguments doit être une chaîne JSON valide, par exemple :
{
"city": "Singapore",
"unit": "c"
}
Ajoutez ces tests dans l'onglet Tests :
pm.test("Tool was called", () => {
const body = pm.response.json();
const call = body.choices[0].message.tool_calls?.[0];
pm.expect(call?.function?.name).to.eql("get_weather");
});
pm.test("Arguments parse as valid JSON", () => {
const body = pm.response.json();
const argsRaw = body.choices[0].message.tool_calls[0].function.arguments;
const args = JSON.parse(argsRaw);
pm.expect(args.city).to.be.a("string");
});
Ces assertions deviennent votre contrat. Si la forme de réponse change, le test échoue avant que votre application ne casse en production.
Étape 6 : tester les erreurs et les limites de débit
Créez des requêtes dédiées pour les scénarios d'erreur prévisibles.
| Scénario | Comment déclencher | Attendu |
|---|---|---|
| Clé invalide | Définir OPENAI_API_KEY sur sk-bad dans un environnement Sandbox
|
401 avec error.code = "invalid_api_key"
|
| Limite de débit | Exécuter la requête 200 fois dans le collection runner Apidog |
429 avec l'en-tête Retry-After
|
| Limite de jetons dépassée | Envoyer un prompt de 200K jetons à un modèle de contexte de 128K |
400 avec error.code = "context_length_exceeded"
|
| Nom de modèle incorrect | Utiliser "model": "gpt-99"
|
404 |
| Violation de schéma | Appel d'outil avec strict: true et entrée malformée |
Le modèle rejette l'outil ou renvoie du texte brut |
Exemple d'assertion pour une clé invalide :
pm.test("Invalid key returns 401", () => {
pm.response.to.have.status(401);
});
pm.test("Error code is invalid_api_key", () => {
const body = pm.response.json();
pm.expect(body.error.code).to.eql("invalid_api_key");
});
Exemple pour une limite de débit :
pm.test("Rate limit returns 429", () => {
pm.response.to.have.status(429);
});
pm.test("Retry-After header exists", () => {
pm.expect(pm.response.headers.get("Retry-After")).to.not.be.null;
});
Ne codez pas un backoff fixe sans lire Retry-After. Cet en-tête est souvent en secondes, parfois avec une valeur fractionnaire.
Étape 7 : simuler ChatGPT pour le frontend
Votre équipe frontend peut avoir besoin de travailler avant que le prompt backend soit stable, ou sans consommer le budget OpenAI.
Dans Apidog :
- Faites un clic droit sur
chat-completion-basic. - Choisissez Smart Mock.
- Activez le mock.
Apidog génère une réponse compatible avec le schéma OpenAI :
idobjectcreatedmodelchoicesusage
L'URL de mock ressemble à ceci :
https://mock.apidog.com/m1/<projectId>/chat/completions
Elle accepte le même body que l'API réelle.
Pour un frontend qui consomme du SSE, configurez un mock avancé qui écrit des fragments au format :
data: { ... }
data: { ... }
data: [DONE]
Avec un intervalle court, par exemple 50 ms, l'interface peut tester :
- affichage token par token
- état de chargement
- bouton stop
- rendu progressif
- cartes d'appel d'outils
Quand le prompt réel est prêt, remplacez simplement l'URL de base par :
https://api.openai.com/v1
Le contrat de requête reste identique.
Étape 8 : créer un scénario de test CI
Les scénarios Apidog permettent d'enchaîner plusieurs requêtes avec assertions.
Créez un scénario qui exécute :
-
chat-completion-basic- vérifie
status === 200 - vérifie
usage.total_tokens > 0
- vérifie
-
chat-completion-stream- vérifie que le flux se termine par
[DONE]
- vérifie que le flux se termine par
-
chat-completion-tools- vérifie que
tool_callsexiste - vérifie que
function.argumentsest un JSON valide
- vérifie que
-
Les scénarios d'erreur de l'étape 6
- vérifie les statuts attendus
- vérifie les codes d'erreur utiles
Exportez le scénario, puis exécutez-le en CI :
apidog-cli run scenario.json --env "OpenAI Prod"
Ajoutez cette commande dans le pipeline de PR qui modifie vos prompts. Chaque changement est alors testé contre l'API OpenAI avant merge.
Coût : quelques appels API.
Bénéfice : les régressions de prompt deviennent des tests rouges, pas des incidents de production.
FAQ
Cela fonctionne-t-il avec Azure OpenAI ?
Oui. Remplacez baseUrl par l'URL de votre ressource Azure, ajoutez le paramètre api-version, puis utilisez l'en-tête api-key au lieu de l'authentification Bearer. Les corps de requête restent similaires.
Puis-je tester les modèles de raisonnement o1 et o3 ?
Oui, mais ces modèles rejettent certains paramètres comme :
temperaturetop_ppresence_penaltyfrequency_penalty
Créez un dossier séparé Reasoning avec un body simplifié.
Comment versionner les prompts dans Apidog ?
Utilisez les branches Apidog. Créez une branche par expérience de prompt, exécutez le scénario de test, comparez l'utilisation des jetons et la qualité des réponses, puis fusionnez. C'est le même flux que pour le code, appliqué aux prompts.
Et le point de terminaison /v1/responses ?
Créez un dossier dédié. L'authentification et l'URL de base sont les mêmes ; seule la forme du body change. Gardez /chat/completions et /responses séparés pour pouvoir les tester en A/B avec les mêmes prompts.
Apidog facture-t-il par appel API ?
Non. OpenAI facture par jeton. Apidog ne s'intercale pas entre vous et OpenAI pour facturer les appels.
En résumé
L'API ChatGPT continuera d'évoluer. Le streaming changera, les schémas d'outils deviendront plus stricts, et certains modèles continueront à rejeter des paramètres que vous pensiez stables.
La défense pratique :
- une collection de requêtes contrôlée
- des assertions sur les réponses critiques
- des mocks pour le frontend
- un scénario CI exécuté avant chaque PR de prompt
Téléchargez Apidog, importez vos appels OpenAI existants, puis construisez ces requêtes une fois. Chaque future mise à jour de ChatGPT deviendra une exécution de test contrôlée au lieu d'un incident de production.
Top comments (0)