parent
b8f9ee0e76
commit
5aba64eb5f
@ -0,0 +1,26 @@ |
||||
import { createOpenmeteoClient } from './openmeteo'; |
||||
|
||||
describe('createOpenmeteoClient', () => { |
||||
const client = createOpenmeteoClient(); |
||||
it('returns some weather for the sample address', async () => { |
||||
const result = await client.getCurrentWeather({ |
||||
latitude: 52.28, |
||||
longitude: 10.52, |
||||
}); |
||||
expect(result.apparentTemperature).toMatch(/^\d+(\.?\d+)?°C$/); |
||||
expect(result.temperature).toMatch(/^\d+(\.?\d+)?°C$/); |
||||
expect(result.relativeHumidity).toMatch(/^\d+%$/); |
||||
|
||||
// Just to make sure that the returned weather seems to be reasonable
|
||||
expect(result).not.toEqual({ |
||||
apparentTemperature: '0°C', |
||||
temperature: '0°C', |
||||
relativeHumidity: '0%', |
||||
}); |
||||
expect(result).not.toEqual({ |
||||
apparentTemperature: '0.0°C', |
||||
temperature: '0.0°C', |
||||
relativeHumidity: '0%', |
||||
}); |
||||
}); |
||||
}); |
@ -0,0 +1,68 @@ |
||||
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}¤t=${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'), |
||||
//...
|
||||
}; |
||||
}), |
||||
}; |
||||
}; |
@ -0,0 +1,10 @@ |
||||
export type WeatherProvider = { |
||||
getCurrentWeather(params: { |
||||
longitude: number; |
||||
latitude: number; |
||||
}): Promise<{ |
||||
temperature: string; |
||||
apparentTemperature: string; |
||||
relativeHumidity: string; |
||||
}>; |
||||
}; |
Loading…
Reference in new issue