Small Nest.js-based project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

64 lines
2.1 KiB

import { compact } from 'lodash';
import NodeGeocoder from 'node-geocoder';
import fetch from 'node-fetch';
import PQueue from 'p-queue';
import { mean } from '../../utils/math';
import type { GeocodingProvider } from './types';
export const createOsmClient = (): GeocodingProvider => {
const geocoder = NodeGeocoder({
provider: 'openstreetmap',
fetch: (url, options) => {
return fetch(url, {
...options,
headers: {
...options?.headers,
'user-agent':
'test-assignment-parcellab by Inga. This agent is only supposed to send a few requests in two weeks starting on October 23th 2023, and none after that',
},
});
},
});
// Rate limit according to https://operations.osmfoundation.org/policies/nominatim/
const queue = new PQueue({
interval: 1000,
intervalCap: 1,
timeout: 2000,
throwOnTimeout: true,
});
return {
geocode: async (query) =>
queue.add(async () => {
const result = await geocoder.geocode(query);
if (!result.length) {
throw new Error('No results found');
}
const meanLatitude = mean(
compact(result.map(({ latitude }) => latitude)),
);
const meanLongitude = mean(
compact(result.map(({ longitude }) => longitude)),
);
if (
!result.every(
({ latitude, longitude }) =>
latitude &&
longitude &&
Math.abs(latitude - meanLatitude) < 0.01 &&
Math.abs(longitude - meanLongitude) < 0.01,
)
) {
throw new Error('Ambiguous address');
}
return {
latitude: meanLatitude,
longitude: meanLongitude,
};
}),
};
};