Skip to content

Commit

Permalink
Merge pull request #45 from camptocamp/ogc-api-use-cache
Browse files Browse the repository at this point in the history
Use sharedFetch in OGC API endpoint queries
  • Loading branch information
jahow authored May 29, 2024
2 parents ddbb5b0 + 03ec923 commit e9b434a
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 12 deletions.
12 changes: 10 additions & 2 deletions src/ogc-api/endpoint.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const FIXTURES_ROOT = path.join(__dirname, '../../fixtures/ogc-api');

// setup fetch to read local fixtures
beforeAll(() => {
window.fetch = async (urlOrInfo) => {
window.fetch = jest.fn().mockImplementation(async (urlOrInfo) => {
const url = new URL(
urlOrInfo instanceof URL || typeof urlOrInfo === 'string'
? urlOrInfo
Expand Down Expand Up @@ -48,7 +48,7 @@ beforeAll(() => {
resolve(JSON.parse(contents));
}),
} as Response;
};
});
});

jest.useFakeTimers();
Expand All @@ -75,6 +75,14 @@ describe('OgcApiEndpoint', () => {
'Contains OS data © Crown copyright and database right 2021.',
});
});
it('uses shared fetch', async () => {
jest.clearAllMocks();
// create the endpoint three times separately
new OgcApiEndpoint('http://local/sample-data/').info;
new OgcApiEndpoint('http://local/sample-data/').info;
new OgcApiEndpoint('http://local/sample-data/').info;
expect(window.fetch).toHaveBeenCalledTimes(1);
});
});
describe('#conformanceClasses', () => {
it('returns conformance classes', async () => {
Expand Down
9 changes: 2 additions & 7 deletions src/ogc-api/link-utils.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import { OgcApiDocument, OgcApiDocumentLink } from './model.js';
import { EndpointError } from '../shared/errors.js';
import { getFetchOptions } from '../shared/http-utils.js';
import { sharedFetch } from '../shared/http-utils.js';

export function fetchDocument<T extends OgcApiDocument>(
url: string
): Promise<T> {
const urlObj = new URL(url, window.location.toString());
urlObj.searchParams.set('f', 'json');
const options = getFetchOptions();
const optionsHeaders = 'headers' in options ? options.headers : {};
return fetch(urlObj.toString(), {
...options,
headers: { ...optionsHeaders, Accept: 'application/json' },
}).then((resp) => {
return sharedFetch(urlObj.toString(), 'GET', true).then((resp) => {
if (!resp.ok) {
throw new Error(`The document at ${urlObj} could not be fetched.`);
}
Expand Down
1 change: 1 addition & 0 deletions src/shared/http-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ describe('HTTP utils', () => {
'http://localhost/hello.json?f=json',
{
...sampleOptions,
method: 'GET',
headers: {
...sampleOptions.headers,
Accept: 'application/json',
Expand Down
19 changes: 16 additions & 3 deletions src/shared/http-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,27 @@ export function setFetchOptionsUpdateCallback(
* identical concurrent requests
* Note: this should only be used for GET requests!
*/
export function sharedFetch(url: string, method: 'GET' | 'HEAD' = 'GET') {
const fetchKey = `${method}#${url}`;
export function sharedFetch(
url: string,
method: 'GET' | 'HEAD' = 'GET',
asJson?: boolean
) {
let fetchKey = `${method}#${url}`;
if (asJson) {
fetchKey = `${method}#asJson#${url}`;
}
if (fetchPromises.has(fetchKey)) {
return fetchPromises.get(fetchKey);
}
const options: RequestInit = { ...getFetchOptions() };
options.method = method;
if (asJson) {
options.headers = 'headers' in options ? options.headers : {};
options.headers['Accept'] = 'application/json';
}
// to avoid unhandled promise rejections this promise will never reject,
// but only return errors as a normal value
const promise = fetch(url, { ...getFetchOptions(), method })
const promise = fetch(url, options)
.catch((e) => e)
.then((resp) => {
fetchPromises.delete(fetchKey);
Expand Down

0 comments on commit e9b434a

Please sign in to comment.