diff --git a/src/ogc-api/endpoint.spec.ts b/src/ogc-api/endpoint.spec.ts index 8149baf..caeb750 100644 --- a/src/ogc-api/endpoint.spec.ts +++ b/src/ogc-api/endpoint.spec.ts @@ -1519,6 +1519,19 @@ describe('OgcApiEndpoint', () => { }); }); }); + describe('#getCollectionItemsUrl', () => { + it('returns the correct URL for the collection items', () => { + expect( + endpoint.getCollectionItemsUrl('airports', { + limit: 101, + query: 'name=Sumburgh Airport', + outputFormat: 'json', + }) + ).resolves.toEqual( + 'https://my.server.org/sample-data/collections/airports/items?f=json&name=Sumburgh+Airport&limit=101' + ); + }); + }); }); describe('a failure happens while parsing the endpoint capabilities', () => { beforeEach(() => { diff --git a/src/ogc-api/endpoint.ts b/src/ogc-api/endpoint.ts index 490f688..c5ae107 100644 --- a/src/ogc-api/endpoint.ts +++ b/src/ogc-api/endpoint.ts @@ -24,6 +24,7 @@ import { getLinkUrl, } from './link-utils.js'; import { EndpointError } from '../shared/errors.js'; +import { BoundingBox, CrsCode, MimeType } from '../shared/models.js'; /** * Represents an OGC API endpoint advertising various collections and services. @@ -245,4 +246,60 @@ export default class OgcApiEndpoint { }) .then(fetchDocument); } + + /** + * Asynchronously retrieves a URL for the items of a specified collection, with optional query parameters. + * @param collectionId - The unique identifier for the collection. + * @param options - An object containing optional parameters: + * - query: Additional query parameters to be included in the URL. + * - outputFormat: The MIME type for the output format. Default is 'json'. + * - limit: The maximum number of features to include. + * - extent: Bounding box to limit the features. + * - offset: Pagination offset for the returned results. + * - outputCrs: Coordinate Reference System code for the output. + * - extentCrs: Coordinate Reference System code for the bounding box. + * @returns A promise that resolves to the URL as a string or rejects if an error occurs. + */ + getCollectionItemsUrl( + collectionId: string, + options: { + query?: string; + outputFormat?: MimeType; + limit?: number; + offset?: number; + outputCrs?: CrsCode; + extent?: BoundingBox; + extentCrs?: CrsCode; + } = {} + ): Promise { + return this.getCollectionDocument(collectionId) + .then((collectionDoc) => { + const baseUrl = this.baseUrl || ''; + const itemsLink = getLinkUrl(collectionDoc, 'items', baseUrl); + const url = new URL(itemsLink); + + // Set the format to JSON if not specified + const format = options.outputFormat || 'json'; + url.searchParams.set('f', format); + + if (options.query !== undefined) + url.search += (url.search ? '&' : '') + options.query; + if (options.limit !== undefined) + url.searchParams.set('limit', options.limit.toString()); + if (options.offset !== undefined) + url.searchParams.set('offset', options.offset.toString()); + if (options.outputCrs !== undefined) + url.searchParams.set('crs', options.outputCrs); + if (options.extent !== undefined && options.extent.length === 4) + url.searchParams.set('bbox', options.extent.join(',')); + if (options.extentCrs !== undefined) + url.searchParams.set('bbox-crs', options.extentCrs); + + return url.toString(); + }) + .catch((error) => { + console.error('Error fetching collection items URL:', error); + throw error; + }); + } }