Geocoder is a Typescript library which helps you build geo-aware applications by providing a powerful abstraction layer for geocoding manipulations.
- Installation
- Usage
- Providers
- Special Geocoders and Providers
- Versioning
- Contributing
- Unit Tests
- Background
- License
$ npm i @goparrot/geocoder reflect-metadata axios
In the code snippet below we use Google provider.
import 'reflect-metadata';
import { Distance, Location, Geocoder, GoogleMapsProvider, Suggestion } from '@goparrot/geocoder';
import axios, { AxiosInstance } from 'axios';
const axios: AxiosInstance = axios.create();
const provider: GoogleMapsProvider = new GoogleMapsProvider(axios, 'YOUR_API_KEY');
const geocoder: Geocoder = new Geocoder(provider);
(async () => {
try {
const locations: Location[] = await geocoder.geocode({
address: '1158 E 89th St, Chicago, IL 60619, USA',
});
console.info({ locations });
} catch (err) {
console.error(err);
}
try {
const locations: Location[] = await geocoder.reverse({
lat: 41.7340186,
lon: -87.5960762,
});
console.info({ locations });
} catch (err) {
console.error(err);
}
try {
const suggestions: Suggestion[] = await geocoder.suggest({
address: '1158 E 89th St',
});
console.info({ suggestions });
} catch (err) {
console.error(err);
}
try {
const location: Location = await geocoder.placeDetails({
placeId: 'SOME_GOOGLE_PLACE_ID',
});
console.info({ location });
} catch (err) {
console.error(err);
}
try {
const distance: Distance = await geocoder.distance({
from: {
lat: 40.871994,
lon: -74.425937,
},
to: {
lat: 40.863008,
lon: -74.385286,
},
mode: TravelModeEnum.DRIVING,
});
console.info({ distance });
} catch (err) {
console.error(err);
}
})();
In the code snippet below we use Here provider.
import 'reflect-metadata';
import { Location, Geocoder, HereProvider, LoggerInterface } from '@goparrot/geocoder';
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
// You can use any logger that fits the LoggerInterface
const logger: LoggerInterface = console;
// Set timeout for all requests
const axios: AxiosInstance = axios.create({
timeout: 5000,
});
// You can log all requests
axios.interceptors.request.use((request: AxiosRequestConfig) => {
logger.debug('api request', request);
return request;
});
// You can log all responses
axios.interceptors.response.use((response: AxiosResponse): AxiosResponse => {
logger.debug(`api response ${response.status}`, response.data);
return response;
});
/**
* Caching adapter for axios. Store request results in a configurable store to prevent unneeded network requests.
* @link {https://github.com/RasCarlito/axios-cache-adapter}
*/
const provider: HereProvider = new HereProvider(axios, 'YOUR_APP_ID', 'YOUR_APP_CODE');
const geocoder: Geocoder = new Geocoder(provider);
geocoder.setLogger(logger);
(async () => {
try {
const locations: Location[] = await geocoder.geocode({
// accuracy: AccuracyEnum.HOUSE_NUMBER,
address: '1158 E 89th St, Chicago, IL 60619, USA',
countryCode: 'US',
// postalCode: '60619',
// state: 'Illinois',
// stateCode: 'IL',
// city: 'Chicago',
// language: 'en', // default
// limit: 5, // default
// fillMissingQueryProperties: true, // default
withRaw: true, // default false
});
logger.info('locations', { locations });
} catch (err) {
logger.error(err);
}
try {
const locations: Location[] = await geocoder.reverse({
// accuracy: AccuracyEnum.HOUSE_NUMBER,
lat: 41.7340186,
lon: -87.5960762,
countryCode: 'US',
// language: 'en', // default
// limit: 5, // default
// withRaw: false, // default
});
console.info('locations', { locations });
} catch (err) {
console.error(err);
}
})();
Legend:
- β - Implemented / ready to use
- π« - Provider doesn't support it
- β - In progress
- π - Need help with implementation
- ποΈ - Need to investigate if supported by provider
Provider | Geocode | Reverse | Suggest | Place Details | Distance |
---|---|---|---|---|---|
Algolia Places | π | ποΈ | π | π | π |
ArcGIS Online | β | β | β οΈ | β | π |
Bing Maps | π | ποΈ | ποΈ | π | π |
Geonames | π | ποΈ | ποΈ | π | π |
Google Maps | β | β | β | β | β |
Here | β | β | β | β | π |
LocationIQ | π | ποΈ | ποΈ | π | π |
Mapbox | π | ποΈ | ποΈ | π | π |
MapQuest | β | β | π«οΈ | π« | π |
Mapzen | π | ποΈ | ποΈ | π | π |
Nominatim | π | ποΈ | ποΈ | π | π |
OpenCage | π | ποΈ | ποΈ | π | π |
Photon | π | ποΈ | ποΈ | π | π |
PickPoint | π | ποΈ | ποΈ | π | π |
TomTom | π | ποΈ | ποΈ | π | π |
Yandex | π | ποΈ | ποΈ | π | ποΈ |
The ChainProvider
is a special provider that takes a list of providers and
iterates over this list to get information. Note that it stops its iteration
when a provider returns a result.
import 'reflect-metadata';
import axios, { AxiosInstance } from 'axios';
import { Location, ChainProvider, HereProvider, MapQuestProvider, ProviderAggregator } from '@goparrot/geocoder';
const axios: AxiosInstance = axios.create({
timeout: 5000,
});
const chainProvider: ChainProvider = new ChainProvider([new MapQuestProvider(axios, 'YOUR_API_KEY'), new HereProvider(axios, 'YOUR_APP_ID', 'YOUR_APP_CODE')]);
const geocoder: ProviderAggregator = new ProviderAggregator([chainProvider]);
(async () => {
try {
const locations: Location[] = await geocoder.geocode({
address: '1158 E 89th St, Chicago, IL 60619, USA',
});
console.info({ locations });
} catch (err) {
console.error(err);
}
})();
The ProviderAggregator
is used to register several providers so that you can
manualy decide which provider to use later on.
import 'reflect-metadata';
import axios, { AxiosInstance } from 'axios';
import { Location, GoogleMapsProvider, HereProvider, ProviderAggregator, MapQuestProvider } from '@goparrot/geocoder';
const axios: AxiosInstance = axios.create({
timeout: 5000,
});
const geocoder: ProviderAggregator = new ProviderAggregator([
new MapQuestProvider(axios, 'YOUR_API_KEY'),
new HereProvider(axios, 'YOUR_APP_ID', 'YOUR_APP_CODE'),
]);
geocoder.registerProvider(new GoogleMapsProvider(axios, 'YOUR_API_KEY'));
(async () => {
try {
const locations: Location[] = await geocoder.using(GoogleMapsProvider).geocode({
address: '1158 E 89th St, Chicago, IL 60619, USA',
});
console.info({ locations });
} catch (err) {
console.error(err);
}
})();
The ProviderAggregator
's API is fluent, meaning you can write:
const locations: Location[] = geocoder.registerProvider(new MyCustomProvider(axios)).using(MyCustomProvider).geocode({
// ...
});
The using()
method allows you to choose the provider
to use by its class name.
When you deal with multiple providers, you may want to choose one of them. The
default behavior is to use the first one, but it can be annoying.
Geocoder follows Semantic Versioning.
See CONTRIBUTING
file.
In order to run the test suite, install the development dependencies:
$ npm i
Then, run the following command:
$ npm run coverage
Inspired by geocoder-php/geocoder
Geocoder is MIT licensed.