From d4591d34633f5526b623b3db6516364f29d79f37 Mon Sep 17 00:00:00 2001 From: Caroline Vantim Date: Fri, 31 Mar 2023 09:17:00 -0300 Subject: [PATCH] add Geoapify Provider --- .env.sample | 1 + README.md | 6 +- docs/lib/providers.ts | 5 + docs/providers/geoapify.mdx | 40 ++++++++ doczrc.js | 1 + src/index.ts | 1 + .../__tests__/geoapifyProvider.spec.js | 39 ++++++++ src/providers/__tests__/geoapifyResponse.json | 65 +++++++++++++ src/providers/geoapifyProvider.ts | 95 +++++++++++++++++++ src/providers/index.ts | 1 + 10 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 docs/providers/geoapify.mdx create mode 100644 src/providers/__tests__/geoapifyProvider.spec.js create mode 100644 src/providers/__tests__/geoapifyResponse.json create mode 100644 src/providers/geoapifyProvider.ts diff --git a/.env.sample b/.env.sample index 160594601..5fa237c0c 100644 --- a/.env.sample +++ b/.env.sample @@ -3,3 +3,4 @@ GOOGLE_API_KEY=___YOUR_KEY___ LOCATIONIQ_API_KEY=___YOUR_KEY___ OPENCAGE_API_KEY=___YOUR_KEY___ HERE_API_KEY=___YOUR_KEY___ +GEOAPIFY_API_KEY=___YOUR_KEY___ diff --git a/README.md b/README.md index 8c013829c..28123176c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # Leaflet.GeoSearch + [![All Contributors](https://img.shields.io/badge/all_contributors-53-orange.svg?style=flat-square)](#contributors-) + **Demo and Docs: [smeijer.github.io/leaflet-geosearch](https://smeijer.github.io/leaflet-geosearch)** @@ -58,6 +60,7 @@ The control comes with a number of default providers: - [Pelias] - [Mapbox](https://docs.mapbox.com/help/tutorials/local-search-geocoding-api/) - [GeoApiFR](https://geo.api.gouv.fr/adresse) +- [Geoapify](https://apidocs.geoapify.com/docs/geocoding/forward-geocoding/#about) Although this project is still named `leaflet-geosearch`, this library is also usable without LeafletJS, and does not have any dependencies whatsoever. @@ -424,10 +427,11 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Paul Schreiber
Paul Schreiber

💻 Nick Silvestri
Nick Silvestri

🤔 💻 teriblus
teriblus

💻 + Caroline Vantim
Caroline Vantim

💻 - + diff --git a/docs/lib/providers.ts b/docs/lib/providers.ts index 3315c9e02..cc1a8b25a 100644 --- a/docs/lib/providers.ts +++ b/docs/lib/providers.ts @@ -11,6 +11,7 @@ import { OpenStreetMapProvider, PeliasProvider, GeoApiFrProvider, + GeoapifyProvider, } from 'leaflet-geosearch'; export default { @@ -44,6 +45,10 @@ export default { params: { key: process.env.GATSBY_OPENCAGE_API_KEY }, }), + Geoapify: new GeoapifyProvider({ + params: { apiKey: process.env.GATSBY_GEOAPIFY_API_KEY }, + }), + OpenStreetMap: new OpenStreetMapProvider(), Pelias: new PeliasProvider(), diff --git a/docs/providers/geoapify.mdx b/docs/providers/geoapify.mdx new file mode 100644 index 000000000..76e38a2dc --- /dev/null +++ b/docs/providers/geoapify.mdx @@ -0,0 +1,40 @@ +--- +name: Geoapify +menu: Providers +route: /providers/geoapify +--- + +import Playground from '../components/Playground'; +import Map from '../components/Map'; + +# Geoapify Provider + +**note**: Geoapify services require an API key. [Obtain geoapify][1]. +For more options and configurations, see the [Geoapify developer docs][2]. + + + + + +```js +import { GeoapifyProvider } from 'leaflet-geosearch'; + +const provider = new GeoapifyProvider({ + params: { + apiKey: '__YOUR_HERE_KEY__', + }, +}); + +// add to leaflet +import { GeoSearchControl } from 'leaflet-geosearch'; + +map.addControl( + new GeoSearchControl({ + provider, + style: 'bar', + }), +); +``` + +[1]: https://apidocs.geoapify.com/ +[2]: https://apidocs.geoapify.com/docs/geocoding/forward-geocoding/#geocode-addresses diff --git a/doczrc.js b/doczrc.js index 6d6294db5..c9b886f98 100644 --- a/doczrc.js +++ b/doczrc.js @@ -28,6 +28,7 @@ export default { 'OpenStreetMap', 'Pelias', 'Custom Providers', + 'Geoapify', ], }, ], diff --git a/src/index.ts b/src/index.ts index eb196a4a2..be9ea1063 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,5 +15,6 @@ export { default as OpenStreetMapProvider } from './providers/openStreetMapProvi export { default as PeliasProvider } from './providers/peliasProvider'; export { default as MapBoxProvider } from './providers/mapBoxProvider'; export { default as GeoApiFrProvider } from './providers/geoApiFrProvider'; +export { default as GeoapifyProvider } from './providers/geoapifyProvider'; export { default as JsonProvider } from './providers/provider'; diff --git a/src/providers/__tests__/geoapifyProvider.spec.js b/src/providers/__tests__/geoapifyProvider.spec.js new file mode 100644 index 000000000..421ec5ca9 --- /dev/null +++ b/src/providers/__tests__/geoapifyProvider.spec.js @@ -0,0 +1,39 @@ +import Provider from '../geoapifyProvider'; +import fixtures from './geoapifyResponse.json'; + +describe('Geoapify', () => { + beforeAll(() => { + fetch.mockResponse(async () => ({ body: JSON.stringify(fixtures) })); + }); + + test('Can fetch results', async () => { + const provider = new Provider({ + params: { + apiKey: process.env.GEOAPIFY_API_KEY, + }, + }); + + const results = await provider.search({ query: 'Chicago' }); + const result = results[0]; + + expect(result.label).toBeTruthy(); + expect(result.x).toEqual(+fixtures.results[0].lon); + expect(result.y).toEqual(+fixtures.results[0].lat); + expect(result.bounds).toBeValidBounds(); + }); + + test.skip('Can get localized results', async () => { + const provider = new Provider({ + params: { + apiKey: process.env.GEOAPIFY_API_KEY, + 'accept-language': 'nl', + }, + }); + + const results = await provider.search({ query: 'Chicago' }); + t.is( + results[0].label, + '1214-1224 West Van Buren Street, Chicago, IL 60607, United States of America' + ); + }); +}); diff --git a/src/providers/__tests__/geoapifyResponse.json b/src/providers/__tests__/geoapifyResponse.json new file mode 100644 index 000000000..763a19f6b --- /dev/null +++ b/src/providers/__tests__/geoapifyResponse.json @@ -0,0 +1,65 @@ +{ + "results": [ + { + "datasource": { + "sourcename": "openstreetmap", + "attribution": "© OpenStreetMap contributors", + "license": "Open Database License", + "url": "https://www.openstreetmap.org/copyright" + }, + "country": "United States", + "country_code": "us", + "state": "Illinois", + "county": "Cook County", + "city": "Chicago", + "postcode": "60607", + "suburb": "Near West Side", + "street": "West Van Buren Street", + "housenumber": "1214-1224", + "lon": -87.65816734222005, + "lat": 41.87695205, + "state_code": "IL", + "formatted": "1214-1224 West Van Buren Street, Chicago, IL 60607, United States of America", + "address_line1": "1214-1224 West Van Buren Street", + "address_line2": "Chicago, IL 60607, United States of America", + "category": "building", + "timezone": { + "name": "America/Chicago", + "offset_STD": "-06:00", + "offset_STD_seconds": -21600, + "offset_DST": "-05:00", + "offset_DST_seconds": -18000, + "abbreviation_STD": "CST", + "abbreviation_DST": "CDT" + }, + "result_type": "building", + "rank": { + "importance": 0.60001, + "popularity": 6.686411370288237, + "confidence": 1, + "confidence_city_level": 1, + "confidence_street_level": 1, + "match_type": "full_match" + }, + "place_id": "515888ea691fea55c0598074fbf63ff04440f00102f9013076880c00000000c00203", + "bbox": { + "lon1": -87.658723, + "lat1": 41.8765924, + "lon2": -87.6576007, + "lat2": 41.8770888 + } + } + ], + "query": { + "text": "1214-1224 West Van Buren Street, Chicago, IL 60607, United States of America", + "parsed": { + "housenumber": "1214-1224", + "street": "west van buren street", + "postcode": "60607", + "city": "chicago", + "state": "il", + "country": "united states of america", + "expected_type": "building" + } + } +} diff --git a/src/providers/geoapifyProvider.ts b/src/providers/geoapifyProvider.ts new file mode 100644 index 000000000..aa826ff45 --- /dev/null +++ b/src/providers/geoapifyProvider.ts @@ -0,0 +1,95 @@ +import AbstractProvider, { + EndpointArgument, + ParseArgument, + ProviderOptions, + RequestType, + SearchResult, +} from './provider'; + +export type RequestResult = { + results: RawResult[]; + query: RawQuery[]; +}; + +export interface RawResult { + country: string; + country_code: string; + state: string; + county: string; + city: string; + postcode: number; + suburb: string; + street: string; + lon: string; + lat: string; + state_code: string; + formatted: string; + bbox: BBox; +} + +export interface RawQuery { + text: string; + parsed: RawQueryParsed; +} + +export type RawQueryParsed = { + city: string; + expected_type: string; +}; + +export type BBox = { + lon1: string; + lat1: string; + lon2: string; + lat2: string; +}; + +export type GeoapifyProviderOptions = { + searchUrl?: string; + reverseUrl?: string; +} & ProviderOptions; + +export default class GeoapifyProvider extends AbstractProvider< + RequestResult, + RawResult +> { + searchUrl: string; + reverseUrl: string; + + constructor(options: GeoapifyProviderOptions = {}) { + super(options); + + const host = 'https://api.geoapify.com/v1/geocode'; + this.searchUrl = options.searchUrl || `${host}/search`; + this.reverseUrl = options.reverseUrl || `${host}/reverse`; + } + + endpoint({ query, type }: EndpointArgument): string { + const params = typeof query === 'string' ? { text: query } : query; + params.format = 'json'; + + switch (type) { + case RequestType.REVERSE: + return this.getUrl(this.reverseUrl, params); + + default: + return this.getUrl(this.searchUrl, params); + } + } + + parse(response: ParseArgument): SearchResult[] { + const records = Array.isArray(response.data.results) + ? response.data.results + : [response.data.results]; + return records.map((r) => ({ + x: Number(r.lon), + y: Number(r.lat), + label: r.formatted, + bounds: [ + [parseFloat(r.bbox.lat1), parseFloat(r.bbox.lon1)], // s, w + [parseFloat(r.bbox.lat2), parseFloat(r.bbox.lon2)], // n, e + ], + raw: r, + })); + } +} diff --git a/src/providers/index.ts b/src/providers/index.ts index d7843d42b..91d464e45 100644 --- a/src/providers/index.ts +++ b/src/providers/index.ts @@ -10,5 +10,6 @@ export { default as OpenStreetMapProvider } from './openStreetMapProvider'; export { default as PeliasProvider } from './peliasProvider'; export { default as MapBoxProvider } from './mapBoxProvider'; export { default as GeoApiFrProvider } from './geoApiFrProvider'; +export { default as GeoapifyProvider } from './geoapifyProvider'; export { default as Provider } from './provider';