Ensure subsequent page reads are run through the proxy
Signed-off-by: Robert Bunning <rbunning@webstaurantstore.com>
This commit is contained in:
@@ -126,7 +126,7 @@ describe('NewRelicClient', () => {
|
||||
headers: new Map<string, string | null>([
|
||||
[
|
||||
'link',
|
||||
'<https://next.page/page2>; rel="next", <https://badsite.dontgohere>; rel="next"',
|
||||
'<https://next.page/page2?page=2>; rel="next", <https://badsite.dontgohere>; rel="next"',
|
||||
],
|
||||
['otherheader', 'otherValue'],
|
||||
]),
|
||||
@@ -135,7 +135,7 @@ describe('NewRelicClient', () => {
|
||||
ok: true,
|
||||
json: async () => ({ applications: [] }),
|
||||
headers: new Map<string, string | null>([
|
||||
['Link', '<https://next.page/page3>; rel="next",'],
|
||||
['Link', '<https://next.page/page3?page=3>; rel="next",'],
|
||||
]),
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
@@ -170,10 +170,10 @@ describe('NewRelicClient', () => {
|
||||
'https://test.test/newrelic/apm/api/applications.json',
|
||||
);
|
||||
expect(mockedFetchApi.fetch).toHaveBeenCalledWith(
|
||||
'https://next.page/page2',
|
||||
'https://test.test/newrelic/apm/api/applications.json?page=2',
|
||||
);
|
||||
expect(mockedFetchApi.fetch).toHaveBeenCalledWith(
|
||||
'https://next.page/page3',
|
||||
'https://test.test/newrelic/apm/api/applications.json?page=3',
|
||||
);
|
||||
expect(actual).toStrictEqual(expected);
|
||||
});
|
||||
@@ -220,6 +220,7 @@ describe('NewRelicClient', () => {
|
||||
['<>; rel:"value"'],
|
||||
['<https://next.page>; rel: "next"'],
|
||||
['ABCDE'],
|
||||
['<https://next.page/page3?page=>; rel="next",'],
|
||||
])(
|
||||
'It does not attempt pagination when the link header value is invalid (%p)',
|
||||
async linkHeaderValue => {
|
||||
@@ -309,4 +310,29 @@ describe('NewRelicClient', () => {
|
||||
|
||||
expect(actual).toStrictEqual({ applications: [] });
|
||||
});
|
||||
|
||||
it('Generates the base url only once', async () => {
|
||||
const mockedDiscoveryApi: DiscoveryApi = {
|
||||
getBaseUrl: jest.fn().mockResolvedValueOnce('https://test.test'),
|
||||
};
|
||||
|
||||
const mockedFetchApi: FetchApi = {
|
||||
fetch: jest.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ applications: [] }),
|
||||
}),
|
||||
};
|
||||
|
||||
const client = new NewRelicClient({
|
||||
discoveryApi: mockedDiscoveryApi,
|
||||
fetchApi: mockedFetchApi,
|
||||
});
|
||||
|
||||
await client.getApplications();
|
||||
await client.getApplications();
|
||||
await client.getApplications();
|
||||
await client.getApplications();
|
||||
|
||||
expect(mockedDiscoveryApi.getBaseUrl).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -91,16 +91,22 @@ export class NewRelicClient implements NewRelicApi {
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
private readonly fetchApi: FetchApi;
|
||||
private readonly proxyPathBase: string;
|
||||
private baseUrl: string;
|
||||
|
||||
constructor(options: Options) {
|
||||
this.discoveryApi = options.discoveryApi;
|
||||
this.fetchApi = options.fetchApi;
|
||||
this.proxyPathBase = options.proxyPathBase ?? DEFAULT_PROXY_PATH_BASE;
|
||||
this.baseUrl = '';
|
||||
}
|
||||
|
||||
async getApplications(): Promise<NewRelicApplications> {
|
||||
const proxyUrl = await this.discoveryApi.getBaseUrl('proxy');
|
||||
let targetUrl = `${proxyUrl}${this.proxyPathBase}/apm/api/applications.json`;
|
||||
if (!this.baseUrl) {
|
||||
const proxyUrl = await this.discoveryApi.getBaseUrl('proxy');
|
||||
this.baseUrl = `${proxyUrl}${this.proxyPathBase}/apm/api/applications.json`;
|
||||
}
|
||||
|
||||
let targetUrl = this.baseUrl;
|
||||
let hasNextPage = true;
|
||||
|
||||
try {
|
||||
@@ -111,7 +117,7 @@ export class NewRelicClient implements NewRelicApi {
|
||||
await this.fetchNewRelic(targetUrl);
|
||||
|
||||
hasNextPage = hasMoreApplications;
|
||||
targetUrl = pagination!.nextPageLink;
|
||||
targetUrl = hasNextPage ? pagination!.nextPageLink : '';
|
||||
applications = applications.concat(applicationsFromReadPage);
|
||||
} while (hasNextPage);
|
||||
|
||||
@@ -155,12 +161,12 @@ export class NewRelicClient implements NewRelicApi {
|
||||
}
|
||||
|
||||
const nextRelevantLink = linkHeader.replaceAll(' ', '').split(',')[0];
|
||||
|
||||
// Link should be of the format <nextPageLink>;rel="relation"
|
||||
const linkParts = nextRelevantLink.match(/^<(.+)>;rel="(.+)"$/);
|
||||
const nextPageLink = linkParts?.[1];
|
||||
const linkParts = nextRelevantLink.match(/^<.+(\?page=.+)>;rel="(.+)"$/);
|
||||
const nextPageNumber = linkParts?.[1];
|
||||
const relation = linkParts?.[2];
|
||||
const isValidLink = !!(!!linkParts && nextPageLink && relation);
|
||||
|
||||
const nextPageLink = `${this.baseUrl}${nextPageNumber}`;
|
||||
const isValidLink = !!(!!linkParts && nextPageNumber && relation);
|
||||
|
||||
if (!nextRelevantLink || !isValidLink) {
|
||||
return undefined;
|
||||
|
||||
Reference in New Issue
Block a user