{"id":13588772,"url":"https://github.com/goparrot/geocoder","last_synced_at":"2025-03-01T04:34:17.257Z","repository":{"id":44462990,"uuid":"171057136","full_name":"goparrot/geocoder","owner":"goparrot","description":"Geocoder is a Typescript library which helps you build geo-aware applications by providing a powerful abstraction layer for geocoding manipulations","archived":false,"fork":false,"pushed_at":"2024-07-05T12:31:56.000Z","size":628,"stargazers_count":31,"open_issues_count":3,"forks_count":8,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-02-20T18:47:25.049Z","etag":null,"topics":["arcgis","autocomplete","geo","geocode","geocoder","geocoding","geolocation","google-maps","here","mapquest","node","nodejs","places","reverse","suggest","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/goparrot.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-16T22:08:40.000Z","updated_at":"2024-05-28T08:50:45.000Z","dependencies_parsed_at":"2024-06-19T00:22:31.278Z","dependency_job_id":"ff9f71dc-d4a8-4612-b92b-1dde83b3784d","html_url":"https://github.com/goparrot/geocoder","commit_stats":{"total_commits":138,"total_committers":7,"mean_commits":"19.714285714285715","dds":0.1811594202898551,"last_synced_commit":"3a9cf759e0dbc3e053adee1a5626375e4623060b"},"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goparrot%2Fgeocoder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goparrot%2Fgeocoder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goparrot%2Fgeocoder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goparrot%2Fgeocoder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goparrot","download_url":"https://codeload.github.com/goparrot/geocoder/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241202225,"owners_count":19926565,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arcgis","autocomplete","geo","geocode","geocoder","geocoding","geolocation","google-maps","here","mapquest","node","nodejs","places","reverse","suggest","typescript"],"created_at":"2024-08-01T15:06:54.988Z","updated_at":"2025-03-01T04:34:17.241Z","avatar_url":"https://github.com/goparrot.png","language":"TypeScript","readme":"[![Build Status](https://github.com/goparrot/geocoder/workflows/CI/badge.svg?branch=master)](https://github.com/goparrot/geocoder/actions?query=branch%3Amaster+event%3Apush+workflow%3ACI)\n[![Coverage Status](https://coveralls.io/repos/github/goparrot/geocoder/badge.svg?branch=master)](https://coveralls.io/github/goparrot/geocoder?branch=master)\n[![NPM version](https://img.shields.io/npm/v/@goparrot/geocoder)](https://www.npmjs.com/package/@goparrot/geocoder)\n[![Greenkeeper badge](https://badges.greenkeeper.io/goparrot/geocoder.svg)](https://greenkeeper.io/)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org)\n\n# Geocoder\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/goparrot/geocoder\" target=\"blank\"\u003e\u003cimg src=\"https://upload.wikimedia.org/wikipedia/commons/7/72/OpenStreetMap-Logo-2006.svg\" width=\"354\" alt=\"Geocoder Logo\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Description\n\n**Geocoder** is a Typescript library which helps you build geo-aware applications by\nproviding a powerful abstraction layer for geocoding manipulations.\n\n*   [Installation](#installation)\n*   [Usage](#usage)\n*   [Providers](#providers)\n*   [Special Geocoders and Providers](#special-geocoders-and-providers)\n*   [Versioning](#versioning)\n*   [Contributing](#contributing)\n*   [Unit Tests](#unit-tests)\n*   [Background](#background)\n*   [License](#license)\n\n## Installation\n\n    $ npm i @goparrot/geocoder reflect-metadata axios\n\n\u003csub\u003e⚠️️ Each reflect-metadata installation has its own metadata storage, from which it reads and writes from.\nSo if you had a project with multiple reflect-metadata packages, it could happen that in one file you write metadata in one reflect-metadata package and in another file you’re trying to retrieve this metadata accidently from the other reflect-metadata package, which of course doesn’t exist there.\u003c/sub\u003e\n\n## Usage\n\n### Minimal\n\nIn the code snippet below we use Google provider.\n\n```typescript\nimport 'reflect-metadata';\nimport { Distance, Location, Geocoder, GoogleMapsProvider, Suggestion } from '@goparrot/geocoder';\nimport axios, { AxiosInstance } from 'axios';\n\nconst axios: AxiosInstance = axios.create();\n\nconst provider: GoogleMapsProvider = new GoogleMapsProvider(axios, 'YOUR_API_KEY');\n\nconst geocoder: Geocoder = new Geocoder(provider);\n\n(async () =\u003e {\n    try {\n        const locations: Location[] = await geocoder.geocode({\n            address: '1158 E 89th St, Chicago, IL 60619, USA',\n        });\n\n        console.info({ locations });\n    } catch (err) {\n        console.error(err);\n    }\n\n    try {\n        const locations: Location[] = await geocoder.reverse({\n            lat: 41.7340186,\n            lon: -87.5960762,\n        });\n\n        console.info({ locations });\n    } catch (err) {\n        console.error(err);\n    }\n\n    try {\n        const suggestions: Suggestion[] = await geocoder.suggest({\n            address: '1158 E 89th St',\n        });\n\n        console.info({ suggestions });\n    } catch (err) {\n        console.error(err);\n    }\n\n    try {\n        const location: Location = await geocoder.placeDetails({\n            placeId: 'SOME_GOOGLE_PLACE_ID',\n        });\n\n        console.info({ location });\n    } catch (err) {\n        console.error(err);\n    }\n\n    try {\n        const distance: Distance = await geocoder.distance({\n            from: {\n                lat: 40.871994,\n                lon: -74.425937,\n            },\n            to: {\n                lat: 40.863008,\n                lon: -74.385286,\n            },\n            mode: TravelModeEnum.DRIVING,\n        });\n\n        console.info({ distance });\n    } catch (err) {\n        console.error(err);\n    }\n})();\n```\n\n### Advanced\n\nIn the code snippet below we use Here provider.\n\n```typescript\nimport 'reflect-metadata';\nimport { Location, Geocoder, HereProvider, LoggerInterface } from '@goparrot/geocoder';\nimport axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';\n\n// You can use any logger that fits the LoggerInterface\nconst logger: LoggerInterface = console;\n\n// Set timeout for all requests\nconst axios: AxiosInstance = axios.create({\n    timeout: 5000,\n});\n\n// You can log all requests\naxios.interceptors.request.use((request: AxiosRequestConfig) =\u003e {\n    logger.debug('api request', request);\n\n    return request;\n});\n\n// You can log all responses\naxios.interceptors.response.use((response: AxiosResponse): AxiosResponse =\u003e {\n    logger.debug(`api response ${response.status}`, response.data);\n\n    return response;\n});\n\n/**\n * Caching adapter for axios. Store request results in a configurable store to prevent unneeded network requests.\n * @link {https://github.com/RasCarlito/axios-cache-adapter}\n */\n\nconst provider: HereProvider = new HereProvider(axios, 'YOUR_APP_ID', 'YOUR_APP_CODE');\n\nconst geocoder: Geocoder = new Geocoder(provider);\ngeocoder.setLogger(logger);\n\n(async () =\u003e {\n    try {\n        const locations: Location[] = await geocoder.geocode({\n            // accuracy: AccuracyEnum.HOUSE_NUMBER,\n            address: '1158 E 89th St, Chicago, IL 60619, USA',\n            countryCode: 'US',\n            // postalCode: '60619',\n            // state: 'Illinois',\n            // stateCode: 'IL',\n            // city: 'Chicago',\n            // language: 'en', // default\n            // limit: 5, // default\n            // fillMissingQueryProperties: true, // default\n            withRaw: true, // default false\n        });\n\n        logger.info('locations', { locations });\n    } catch (err) {\n        logger.error(err);\n    }\n\n    try {\n        const locations: Location[] = await geocoder.reverse({\n            // accuracy: AccuracyEnum.HOUSE_NUMBER,\n            lat: 41.7340186,\n            lon: -87.5960762,\n            countryCode: 'US',\n            // language: 'en', // default\n            // limit: 5, // default\n            // withRaw: false, // default\n        });\n\n        console.info('locations', { locations });\n    } catch (err) {\n        console.error(err);\n    }\n})();\n```\n\n## Providers\n\nLegend:\n\n*   ✅ - Implemented / ready to use\n*   🚫 - Provider doesn't support it\n*   ⌛ - In progress\n*   🆘 - Need help with implementation\n*   🔍️ - Need to investigate if supported by provider\n\n### Location\n\n#### World\n\n| Provider                                                                                  | Geocode | Reverse | Suggest | Place Details | Distance |\n| :---------------------------------------------------------------------------------------- | :------ | :------ | :------ | :------------ | :------- |\n| [Algolia Places](https://community.algolia.com/places/documentation.html)                 | 🆘      | 🆘️     | 🆘      | 🆘            | 🔍       |\n| [ArcGIS Online](https://developers.arcgis.com/documentation/)                             | ✅      | ✅      | ✅️     | ✅            | 🔍       |\n| [Bing Maps](https://docs.microsoft.com/en-us/bingmaps/)                                   | 🆘      | 🆘️     | 🔍️     | 🆘            | 🔍       |\n| [Geonames](http://www.geonames.org/export/web-services.html)                              | 🆘      | 🆘️     | 🔍️     | 🆘            | 🔍       |\n| [Google Maps](https://developers.google.com/maps/documentation/geocoding/)                | ✅      | ✅      | ✅      | ✅            | ✅       |\n| [Here](https://developer.here.com/documentation/geocoder/topics/quick-start-geocode.html) | ✅      | ✅      | ✅      | ✅            | 🔍       |\n| [LocationIQ](https://locationiq.com/docs)                                                 | 🆘      | 🆘️     | 🔍️     | 🔍            | 🔍       |\n| [Mapbox](https://docs.mapbox.com/api)                                                     | 🆘      | 🆘️     | 🔍️     | 🔍            | 🔍       |\n| [MapQuest](http://developer.mapquest.com/web/products/dev-services/geocoding-ws)          | ✅      | ✅      | 🚫️     | 🚫            | 🔍       |\n| [Mapzen](https://www.mapzen.com/documentation/)                                           | 🆘      | 🆘️     | 🔍️     | 🔍            | 🔍       |\n| [Nominatim](https://nominatim.org/release-docs/develop/)                                  | 🆘      | 🆘️     | 🔍️     | 🔍            | 🔍       |\n| [OpenCage](https://opencagedata.com/api)                                                  | 🆘      | 🆘️     | 🔍️     | 🔍            | 🔍       |\n| [Photon](http://doc-api.photonengine.com/en/PUN/current/)                                 | 🆘      | 🆘️     | 🔍️     | 🔍            | 🔍       |\n| [PickPoint](https://pickpoint.io/)                                                        | 🆘      | 🆘️     | 🔍️     | 🔍            | 🔍       |\n| [TomTom](https://developer.tomtom.com/maps-sdk-web/documentation)                         | 🆘      | 🆘️     | 🔍️     | 🔍            | 🔍       |\n| [Yandex](https://tech.yandex.com/maps/)                                                   | 🆘      | 🆘️     | 🔍️     | 🔍            | 🆘️      |\n\n## Special Geocoders and Providers\n\n### The ChainProvider\n\nThe `ChainProvider` is a special provider that takes a list of providers and\niterates over this list to get information. Note that it **stops** its iteration\nwhen a provider returns a result.\n\n```typescript\nimport 'reflect-metadata';\nimport axios, { AxiosInstance } from 'axios';\nimport { Location, ChainProvider, HereProvider, MapQuestProvider, ProviderAggregator } from '@goparrot/geocoder';\n\nconst axios: AxiosInstance = axios.create({\n    timeout: 5000,\n});\n\nconst chainProvider: ChainProvider = new ChainProvider([new MapQuestProvider(axios, 'YOUR_API_KEY'), new HereProvider(axios, 'YOUR_APP_ID', 'YOUR_APP_CODE')]);\n\nconst geocoder: ProviderAggregator = new ProviderAggregator([chainProvider]);\n\n(async () =\u003e {\n    try {\n        const locations: Location[] = await geocoder.geocode({\n            address: '1158 E 89th St, Chicago, IL 60619, USA',\n        });\n\n        console.info({ locations });\n    } catch (err) {\n        console.error(err);\n    }\n})();\n```\n\n### The ProviderAggregator\n\nThe `ProviderAggregator` is used to register several providers so that you can\nmanualy decide which provider to use later on.\n\n```typescript\nimport 'reflect-metadata';\nimport axios, { AxiosInstance } from 'axios';\nimport { Location, GoogleMapsProvider, HereProvider, ProviderAggregator, MapQuestProvider } from '@goparrot/geocoder';\n\nconst axios: AxiosInstance = axios.create({\n    timeout: 5000,\n});\n\nconst geocoder: ProviderAggregator = new ProviderAggregator([\n    new MapQuestProvider(axios, 'YOUR_API_KEY'),\n    new HereProvider(axios, 'YOUR_APP_ID', 'YOUR_APP_CODE'),\n]);\n\ngeocoder.registerProvider(new GoogleMapsProvider(axios, 'YOUR_API_KEY'));\n\n(async () =\u003e {\n    try {\n        const locations: Location[] = await geocoder.using(GoogleMapsProvider).geocode({\n            address: '1158 E 89th St, Chicago, IL 60619, USA',\n        });\n\n        console.info({ locations });\n    } catch (err) {\n        console.error(err);\n    }\n})();\n```\n\nThe `ProviderAggregator`'s API is fluent, meaning you can write:\n\n```typescript\nconst locations: Location[] = geocoder.registerProvider(new MyCustomProvider(axios)).using(MyCustomProvider).geocode({\n    // ...\n});\n```\n\nThe `using()` method allows you to choose the `provider` to use by its class name.\nWhen you deal with multiple providers, you may want to choose one of them. The\ndefault behavior is to use the first one, but it can be annoying.\n\n## Versioning\n\nGeocoder follows [Semantic Versioning](http://semver.org/).\n\n## Contributing\n\nSee [`CONTRIBUTING`](https://github.com/goparrot/geocoder/blob/master/CONTRIBUTING.md#contributing) file.\n\n## Unit Tests\n\nIn order to run the test suite, install the development dependencies:\n\n    $ npm i\n\nThen, run the following command:\n\n    $ npm run coverage\n\n## Background\n\nInspired by [geocoder-php/geocoder](https://github.com/geocoder-php/Geocoder)\n\n## License\n\nGeocoder is [MIT licensed](LICENSE).\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoparrot%2Fgeocoder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoparrot%2Fgeocoder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoparrot%2Fgeocoder/lists"}