diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index b09050c599..7e42a26d9f 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -39,6 +39,8 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", + "@types/parse-link-header": "^2.0.1", + "parse-link-header": "^2.0.0", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/newrelic/src/api/index.test.ts b/plugins/newrelic/src/api/index.test.ts index 70fda9606d..94bdc8ff94 100644 --- a/plugins/newrelic/src/api/index.test.ts +++ b/plugins/newrelic/src/api/index.test.ts @@ -126,7 +126,7 @@ describe('NewRelicClient', () => { headers: new Map([ [ 'link', - '; rel="next", ; rel="next"', + '; rel="next", ; rel="first"', ], ['otherheader', 'otherValue'], ]), diff --git a/plugins/newrelic/src/api/index.ts b/plugins/newrelic/src/api/index.ts index 237fe95fde..ede225dc05 100644 --- a/plugins/newrelic/src/api/index.ts +++ b/plugins/newrelic/src/api/index.ts @@ -20,6 +20,8 @@ import { FetchApi, } from '@backstage/core-plugin-api'; +import parseLinkHeader from 'parse-link-header'; + export type NewRelicApplication = { id: number; application_summary: NewRelicApplicationSummary; @@ -76,14 +78,8 @@ export interface NewRelicApi { getApplications(): Promise; } -interface PaginationInformation { - nextPageLink: string; - relation: string; -} - interface NewRelicPageReadResult { - hasMoreApplications: boolean; - pagination: PaginationInformation | undefined; + nextPageUrl: string | undefined; applicationsFromReadPage: NewRelicApplication[]; } @@ -106,20 +102,17 @@ export class NewRelicClient implements NewRelicApi { this.baseUrl = `${proxyUrl}${this.proxyPathBase}/apm/api/applications.json`; } - let targetUrl = this.baseUrl; - let hasNextPage = true; - try { let applications: NewRelicApplication[] = []; + let targetUrl = this.baseUrl; do { - const { hasMoreApplications, pagination, applicationsFromReadPage } = + const { nextPageUrl, applicationsFromReadPage } = await this.fetchNewRelic(targetUrl); - hasNextPage = hasMoreApplications; - targetUrl = hasNextPage ? pagination!.nextPageLink : ''; + targetUrl = nextPageUrl ?? ''; applications = applications.concat(applicationsFromReadPage); - } while (hasNextPage); + } while (!!targetUrl); return { applications }; } catch (e) { @@ -143,37 +136,12 @@ export class NewRelicClient implements NewRelicApi { const readResponse = responseJson as NewRelicApplications; const linkHeader = response.headers.get('link'); - const pagination = this.parseLinkHeader(linkHeader); + const parseResult = parseLinkHeader(linkHeader); + const nextPageNumber = parseResult?.next?.page; return { - hasMoreApplications: !!(pagination && pagination.relation === 'next'), - pagination, + nextPageUrl: nextPageNumber && `${this.baseUrl}?page=${nextPageNumber}`, applicationsFromReadPage: readResponse.applications, }; } - - private parseLinkHeader( - linkHeader: string | null, - ): PaginationInformation | undefined { - if (!linkHeader) { - return undefined; - } - - const nextRelevantLink = linkHeader.replaceAll(' ', '').split(',')[0]; - const linkParts = nextRelevantLink.match(/^<.+(\?page=.+)>;rel="(.+)"$/); - const nextPageNumber = linkParts?.[1]; - const relation = linkParts?.[2]; - - const nextPageLink = `${this.baseUrl}${nextPageNumber}`; - const isValidLink = !!(linkParts && nextPageNumber && relation); - - if (!nextRelevantLink || !isValidLink) { - return undefined; - } - - return { - nextPageLink, - relation, - }; - } } diff --git a/yarn.lock b/yarn.lock index 3f9b0ee1bc..1399f1d622 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7605,9 +7605,11 @@ __metadata: "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 + "@types/parse-link-header": ^2.0.1 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 msw: ^1.0.0 + parse-link-header: ^2.0.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -17606,6 +17608,13 @@ __metadata: languageName: node linkType: hard +"@types/parse-link-header@npm:^2.0.1": + version: 2.0.1 + resolution: "@types/parse-link-header@npm:2.0.1" + checksum: f76678612511365aefc23704f00f3262fcb1d6bd9c4dd83f783a38e50e3ccf26615f9a62c757952cab5af6f2bd8b3b1763ce391376458afce5fe47c6fe2b80e1 + languageName: node + linkType: hard + "@types/passport-auth0@npm:^1.0.5": version: 1.0.5 resolution: "@types/passport-auth0@npm:1.0.5" @@ -34337,6 +34346,15 @@ __metadata: languageName: node linkType: hard +"parse-link-header@npm:^2.0.0": + version: 2.0.0 + resolution: "parse-link-header@npm:2.0.0" + dependencies: + xtend: ~4.0.1 + checksum: 0e96c6af9910e8f92084b49b8dc6a10dd58db470847d1499f562576180c1ac5e49d18007697f0d538e5f3efdc8ce1d8777641f3ae225302b74af0dd0578b628e + languageName: node + linkType: hard + "parse-path@npm:^7.0.0": version: 7.0.0 resolution: "parse-path@npm:7.0.0" @@ -42745,7 +42763,7 @@ __metadata: languageName: node linkType: hard -"xtend@npm:^4.0.0": +"xtend@npm:^4.0.0, xtend@npm:~4.0.1": version: 4.0.2 resolution: "xtend@npm:4.0.2" checksum: ac5dfa738b21f6e7f0dd6e65e1b3155036d68104e67e5d5d1bde74892e327d7e5636a076f625599dc394330a731861e87343ff184b0047fef1360a7ec0a5a36a