feat(idnot): robust JSON handling with clear ExternalServiceError logs [skip ci]
This commit is contained in:
parent
125e9ac923
commit
fd093aec65
@ -1,7 +1,39 @@
|
|||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { IdNotUser, ECivility, EOfficeStatus, EIdnotRole } from '../../types';
|
import { IdNotUser, ECivility, EOfficeStatus, EIdnotRole } from '../../types';
|
||||||
|
import { ExternalServiceError } from '../../types/errors';
|
||||||
|
import { Logger } from '../../utils/logger';
|
||||||
|
|
||||||
export class IdNotService {
|
export class IdNotService {
|
||||||
|
private static async parseJsonOrThrow(response: Response, context: string): Promise<any> {
|
||||||
|
const contentType = response.headers.get('content-type') || '';
|
||||||
|
try {
|
||||||
|
if (contentType.includes('application/json')) {
|
||||||
|
return await (response as any).json();
|
||||||
|
}
|
||||||
|
const text = await (response as any).text();
|
||||||
|
Logger.error('IdNot non-JSON response', {
|
||||||
|
context,
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
contentType,
|
||||||
|
bodySnippet: text?.slice(0, 200)
|
||||||
|
});
|
||||||
|
throw new ExternalServiceError('IdNot', `Non-JSON response (${response.status} ${response.statusText}): ${text?.slice(0, 120) || 'no body'}`);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof ExternalServiceError) throw err;
|
||||||
|
// json() may throw on invalid JSON
|
||||||
|
const text = await (response as any).text().catch(() => undefined);
|
||||||
|
Logger.error('IdNot JSON parse failed', {
|
||||||
|
context,
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
contentType,
|
||||||
|
parseError: err instanceof Error ? err.message : String(err),
|
||||||
|
bodySnippet: text?.slice(0, 200)
|
||||||
|
});
|
||||||
|
throw new ExternalServiceError('IdNot', `Invalid JSON response (${response.status} ${response.statusText}): ${text?.slice(0, 120) || 'no body'}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
static async exchangeCodeForTokens(code: string) {
|
static async exchangeCodeForTokens(code: string) {
|
||||||
const {
|
const {
|
||||||
IDNOT_CLIENT_ID,
|
IDNOT_CLIENT_ID,
|
||||||
@ -67,12 +99,10 @@ export class IdNotService {
|
|||||||
const url = `${IDNOT_ANNUARY_BASE_URL}/api/pp/v2/personnes/${idNot}/rattachements?${searchParams}`;
|
const url = `${IDNOT_ANNUARY_BASE_URL}/api/pp/v2/personnes/${idNot}/rattachements?${searchParams}`;
|
||||||
|
|
||||||
const response = await fetch(url, { method: 'GET' });
|
const response = await fetch(url, { method: 'GET' });
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Failed to fetch rattachements: ${response.status} ${response.statusText}`);
|
throw new ExternalServiceError('IdNot', `Failed to fetch rattachements: ${response.status} ${response.statusText}`);
|
||||||
}
|
}
|
||||||
|
return await IdNotService.parseJsonOrThrow(response as any, 'getUserRattachements');
|
||||||
return response.json();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getOfficeRattachements(idNot: string) {
|
static async getOfficeRattachements(idNot: string) {
|
||||||
@ -89,13 +119,11 @@ export class IdNotService {
|
|||||||
|
|
||||||
const url = `${IDNOT_ANNUARY_BASE_URL}/api/pp/v2/entites/${idNot}/personnes?` + searchParams;
|
const url = `${IDNOT_ANNUARY_BASE_URL}/api/pp/v2/entites/${idNot}/personnes?` + searchParams;
|
||||||
|
|
||||||
const json = await (
|
const response = await fetch(url, { method: 'GET' });
|
||||||
await fetch(url, {
|
if (!response.ok) {
|
||||||
method: 'GET'
|
throw new ExternalServiceError('IdNot', `Failed to fetch office rattachements: ${response.status} ${response.statusText}`);
|
||||||
})
|
}
|
||||||
).json();
|
return await IdNotService.parseJsonOrThrow(response as any, 'getOfficeRattachements');
|
||||||
|
|
||||||
return json;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getUserData(profileIdn: string) {
|
static async getUserData(profileIdn: string) {
|
||||||
@ -109,13 +137,11 @@ export class IdNotService {
|
|||||||
key: IDNOT_API_KEY
|
key: IDNOT_API_KEY
|
||||||
});
|
});
|
||||||
|
|
||||||
const userData = await (
|
const response = await fetch(`${IDNOT_API_BASE_URL}/api/pp/v2/rattachements/${profileIdn}?` + searchParams, { method: 'GET' });
|
||||||
await fetch(`${IDNOT_API_BASE_URL}/api/pp/v2/rattachements/${profileIdn}?` + searchParams, {
|
if (!response.ok) {
|
||||||
method: 'GET'
|
throw new ExternalServiceError('IdNot', `Failed to fetch user data: ${response.status} ${response.statusText}`);
|
||||||
})
|
}
|
||||||
).json();
|
return await IdNotService.parseJsonOrThrow(response as any, 'getUserData');
|
||||||
|
|
||||||
return userData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getOfficeLocationData(locationsUrl: string) {
|
static async getOfficeLocationData(locationsUrl: string) {
|
||||||
@ -129,13 +155,11 @@ export class IdNotService {
|
|||||||
key: IDNOT_API_KEY
|
key: IDNOT_API_KEY
|
||||||
});
|
});
|
||||||
|
|
||||||
const officeLocationData = await (
|
const response = await fetch(`${IDNOT_API_BASE_URL}${locationsUrl}?` + searchParams, { method: 'GET' });
|
||||||
await fetch(`${IDNOT_API_BASE_URL}${locationsUrl}?` + searchParams, {
|
if (!response.ok) {
|
||||||
method: 'GET'
|
throw new ExternalServiceError('IdNot', `Failed to fetch office location data: ${response.status} ${response.statusText}`);
|
||||||
})
|
}
|
||||||
).json();
|
return await IdNotService.parseJsonOrThrow(response as any, 'getOfficeLocationData');
|
||||||
|
|
||||||
return officeLocationData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getOfficeStatus(statusName: string): EOfficeStatus {
|
static getOfficeStatus(statusName: string): EOfficeStatus {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user