diff --git a/CHANGELOG.md b/CHANGELOG.md index 3072412..adbf00e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ +## v1.0.7 + +- IdNot: correction endpoint API Annuaire selon documentation (`/api/pp/v2/personnes/{id}/rattachements`) +- Ajout logique de retry avec variantes d'URL (avec/sans `/annuaire`) +- Support de multiples formats d'endpoints pour robustesse +- Gestion améliorée des erreurs 404 avec retry automatique + ## v1.0.1 -- IdNot: l’endpoint d’authentification accepte désormais le code en POST `/api/v1/idnot/auth` avec `{ code }` dans le corps. +- IdNot: l'endpoint d'authentification accepte désormais le code en POST `/api/v1/idnot/auth` avec `{ code }` dans le corps. - Handler compatible params/body, recommandation: body JSON. - Rappel déploiement: image Docker consommée par `lecoffre_node` via tag `ext`. diff --git a/package.json b/package.json index 042bf23..63ebedf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lecoffre-back-mini", - "version": "1.0.6", + "version": "1.0.7", "description": "Mini serveur avec une route /api/ping", "main": "dist/server.js", "scripts": { diff --git a/src/services/idnot/index.ts b/src/services/idnot/index.ts index 6daa445..ab51820 100644 --- a/src/services/idnot/index.ts +++ b/src/services/idnot/index.ts @@ -119,25 +119,70 @@ export class IdNotService { throw new Error('Missing IDnot API key or base URL'); } + // Essayer plusieurs variantes d'endpoints selon la documentation API Annuaire V2 + const endpoints = [ + // Format correct selon doc: /api/pp/v2/personnes/{id}/rattachements + `${IDNOT_API_BASE_URL}/api/pp/v2/personnes/${profileIdn}/rattachements`, + // Variante sans /annuaire dans l'URL de base + `${IDNOT_API_BASE_URL.replace('/annuaire', '')}/api/pp/v2/personnes/${profileIdn}/rattachements`, + // Ancien format (fallback) + `${IDNOT_API_BASE_URL}/api/pp/v2/rattachements/${profileIdn}` + ]; + const searchParams = new URLSearchParams({ key: IDNOT_API_KEY }); - const userUrl = `${IDNOT_API_BASE_URL}/api/pp/v2/rattachements/${profileIdn}?` + searchParams; - const userResp = await fetch(userUrl, { method: 'GET' }); - if (!userResp.ok) { - const text = await userResp.text().catch(() => ''); - Logger.error('IdNot getUserData failed', { - url: userUrl, - status: userResp.status, - statusText: userResp.statusText, - bodySnippet: text?.substring(0, 500) - }); - throw new Error(`Failed to fetch user data: ${userResp.status} ${userResp.statusText}`); + for (let i = 0; i < endpoints.length; i++) { + const baseUrl = endpoints[i]; + const userUrl = `${baseUrl}?${searchParams}`; + + try { + Logger.info(`IdNot getUserData attempt ${i + 1}`, { url: userUrl, profileIdn }); + + const userResp = await fetch(userUrl, { method: 'GET' }); + + if (userResp.ok) { + const userData = await userResp.json(); + Logger.info(`IdNot getUserData success`, { url: userUrl, profileIdn }); + return userData; + } + + // Log détaillé pour les erreurs + const text = await userResp.text().catch(() => ''); + Logger.error(`IdNot getUserData attempt ${i + 1} failed`, { + url: userUrl, + profileIdn, + status: userResp.status, + statusText: userResp.statusText, + bodySnippet: text?.substring(0, 500) + }); + + // Si c'est une erreur 4xx (sauf 404), ne pas réessayer + if (userResp.status >= 400 && userResp.status < 500 && userResp.status !== 404) { + throw new ExternalServiceError('IdNot', `Failed to fetch user data: ${userResp.status} ${userResp.statusText}`); + } + + } catch (error) { + Logger.error(`IdNot getUserData attempt ${i + 1} error`, { + url: userUrl, + profileIdn, + error: error instanceof Error ? error.message : String(error) + }); + + // Si c'est la dernière tentative, relancer l'erreur + if (i === endpoints.length - 1) { + throw error; + } + } + + // Attendre un peu avant la prochaine tentative + if (i < endpoints.length - 1) { + await new Promise(resolve => setTimeout(resolve, 200 * (i + 1))); + } } - const userData = await userResp.json(); - - return userData; + + throw new ExternalServiceError('IdNot', 'Failed to fetch user data after all attempts'); } static async getOfficeLocationData(locationsUrl: string) {