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.
 

68 lines
2.2 KiB

import fetch from 'node-fetch';
import PQueue from 'p-queue';
import { WeatherProvider } from './types';
const requestedFields = [
'temperature_2m',
'relativehumidity_2m',
'apparent_temperature',
'is_day',
'precipitation',
'rain',
'showers',
'snowfall',
'weathercode',
'cloudcover',
'pressure_msl',
'surface_pressure',
'windspeed_10m',
'winddirection_10m',
'windgusts_10m',
] as const;
type OpenmeteoKey = (typeof requestedFields)[number];
type OpenmeteoResponse =
| {
current_units?: Record<OpenmeteoKey, string | undefined>;
current?: Record<OpenmeteoKey, string | number | undefined>;
}
| undefined;
export const createOpenmeteoClient = (): WeatherProvider => {
// Rate limit (according to https://open-meteo.com/en/terms it's 10k per day;
// here we set it 1 per second, should be enough for the demo app goal)
const queue = new PQueue({
interval: 1000,
intervalCap: 1,
timeout: 2000,
throwOnTimeout: true,
});
return {
getCurrentWeather: async ({ latitude, longitude }) =>
queue.add(async () => {
const response = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=${requestedFields.join(
',',
)}`,
);
const body = (await response.json()) as OpenmeteoResponse;
if (!body || !body.current || !body.current_units) {
throw new Error('cannot load weather');
}
const { current, current_units } = body;
const getReadableValue = (key: OpenmeteoKey) =>
`${current[key]}${current_units[key]}`;
return {
temperature: getReadableValue('temperature_2m'),
apparentTemperature: getReadableValue(
'apparent_temperature',
),
relativeHumidity: getReadableValue('relativehumidity_2m'),
//...
};
}),
};
};