Skip to content

Commit de73c13

Browse files
committed
fix: implemented-parsing-next-link-from-header
1 parent e09d7b4 commit de73c13

File tree

3 files changed

+53
-32
lines changed

3 files changed

+53
-32
lines changed

sdk/index.ts

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ export class Flagsmith {
329329
url: string,
330330
method: string,
331331
body?: { [key: string]: any }
332-
): Promise<any> {
332+
): Promise<{ response: Response; data: any }> {
333333
const headers: { [key: string]: any } = { 'Content-Type': 'application/json' };
334334
if (this.environmentKey) {
335335
headers['X-Environment-Key'] = this.environmentKey as string;
@@ -361,7 +361,7 @@ export class Flagsmith {
361361
);
362362
}
363363

364-
return data.json();
364+
return { response: data, data: await data.json() };
365365
}
366366

367367
/**
@@ -395,25 +395,41 @@ export class Flagsmith {
395395
const documents: any[] = [];
396396
let url = this.environmentUrl;
397397
let loggedWarning = false;
398+
398399
while (true) {
399-
if (!loggedWarning) {
400-
const elapsedMs = Date.now() - startTime;
401-
if (elapsedMs > this.environmentRefreshIntervalSeconds * 1000) {
402-
this.logger.warn(
403-
`Environment document retrieval exceeded the polling interval of ${this.environmentRefreshIntervalSeconds} seconds.`
404-
);
405-
loggedWarning = true;
400+
try {
401+
if (!loggedWarning) {
402+
const elapsedMs = Date.now() - startTime;
403+
if (elapsedMs > this.environmentRefreshIntervalSeconds * 1000) {
404+
this.logger.warn(
405+
`Environment document retrieval exceeded the polling interval of ${this.environmentRefreshIntervalSeconds} seconds.`
406+
);
407+
loggedWarning = true;
408+
}
406409
}
407-
}
408410

409-
const response = await this.getJSONResponse(url, 'GET');
410-
documents.push(response);
411+
const { response, data } = await this.getJSONResponse(url, 'GET');
412+
413+
documents.push(data);
411414

412-
if (response.links && response.links.next && response.links.next.url) {
413-
url = response.links.next.url;
414-
continue;
415+
const linkHeader = response.headers.get('link');
416+
if (linkHeader) {
417+
const nextMatch = linkHeader.match(/<([^>]+)>;\s*rel="next"/);
418+
419+
if (nextMatch) {
420+
const relativeUrl = decodeURIComponent(nextMatch[1]);
421+
url = new URL(relativeUrl, this.apiUrl).href;
422+
423+
continue;
424+
}
425+
}
426+
break;
427+
} catch (error) {
428+
if (error instanceof FlagsmithAPIError && error.message.includes('502')) {
429+
break;
430+
}
431+
throw error;
415432
}
416-
break;
417433
}
418434

419435
// Compile the document
@@ -473,7 +489,7 @@ export class Flagsmith {
473489
if (!this.environmentFlagsUrl) {
474490
throw new Error('`apiUrl` argument is missing or invalid.');
475491
}
476-
const apiFlags = await this.getJSONResponse(this.environmentFlagsUrl, 'GET');
492+
const { data: apiFlags } = await this.getJSONResponse(this.environmentFlagsUrl, 'GET');
477493
const flags = Flags.fromAPIFlags({
478494
apiFlags: apiFlags,
479495
analyticsProcessor: this.analyticsProcessor,
@@ -494,7 +510,7 @@ export class Flagsmith {
494510
throw new Error('`apiUrl` argument is missing or invalid.');
495511
}
496512
const data = generateIdentitiesData(identifier, traits, transient);
497-
const jsonResponse = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
513+
const { data: jsonResponse } = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
498514
const flags = Flags.fromAPIFlags({
499515
apiFlags: jsonResponse['flags'],
500516
analyticsProcessor: this.analyticsProcessor,

tests/engine/unit/engine.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
environmentWithSegmentOverride,
1313
feature1,
1414
getEnvironmentFeatureStateForFeature,
15-
getEnvironmentFeatureStateForFeatureByName,
1615
identity,
1716
identityInSegment,
1817
segmentConditionProperty,

tests/sdk/flagsmith.test.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,29 @@ test('test_update_environment_handles_paginated_document', async () => {
4848
const env = headers['X-Environment-Key'];
4949

5050
if (url.includes('/environment-document')) {
51-
if (env.startsWith('ser.')) {
52-
const page = pages[callCount];
53-
if (page) {
54-
callCount++;
55-
return Promise.resolve(new Response(JSON.stringify(page), { status: 200 }));
51+
const page = pages[callCount];
52+
if (page) {
53+
callCount++;
54+
55+
const responseHeaders: Record<string, string> = {};
56+
57+
if (page.nextUrl) {
58+
responseHeaders['Link'] = `<${page.nextUrl}>; rel="next"`;
5659
}
60+
61+
return Promise.resolve(
62+
new Response(JSON.stringify(page), {
63+
status: 200,
64+
headers: responseHeaders
65+
})
66+
);
5767
}
58-
return Promise.resolve(
59-
new Response('environment-document called without a server-side key', {
60-
status: 401
61-
})
62-
);
6368
}
6469
return Promise.resolve(new Response('unknown url ' + url, { status: 404 }));
6570
});
6671
};
6772

73+
// Added a field "nextUrl" to indicate the mock there is a next page
6874
const pages = [
6975
{
7076
id: 1,
@@ -118,7 +124,7 @@ test('test_update_environment_handles_paginated_document', async () => {
118124
}
119125
],
120126
identity_overrides: [{ id: 1, identifier: 'user1' }],
121-
links: { next: { url: '/api/v1/environment-document?page=2' } }
127+
nextUrl: '/api/v1/environment-document?page=2'
122128
},
123129
{
124130
id: 1,
@@ -138,7 +144,7 @@ test('test_update_environment_handles_paginated_document', async () => {
138144
},
139145
feature_states: [],
140146
identity_overrides: [{ id: 2, identifier: 'user2' }],
141-
links: { next: { url: '/api/v1/environment-document?page=3' } }
147+
nextUrl: '/api/v1/environment-document?page=3'
142148
},
143149
{
144150
id: 1,
@@ -158,7 +164,7 @@ test('test_update_environment_handles_paginated_document', async () => {
158164
},
159165
feature_states: [],
160166
identity_overrides: [{ id: 2, identifier: 'user3' }],
161-
links: null
167+
nextUrl: null
162168
}
163169
];
164170

0 commit comments

Comments
 (0)