|
| 1 | +import { z, ZodType, ZodTypeAny } from "zod"; |
| 2 | +const generalLocationSchema = z.object({ |
| 3 | + properties: z.object({ |
| 4 | + forecast: z.string(), |
| 5 | + }), |
| 6 | +}); |
| 7 | +const forecastSchema = z.object({ |
| 8 | + properties: z.object({ |
| 9 | + periods: z.array( |
| 10 | + z.object({ |
| 11 | + name: z.string(), |
| 12 | + detailedForecast: z.string(), |
| 13 | + }) |
| 14 | + ), |
| 15 | + }), |
| 16 | +}); |
| 17 | +const rootApiURL = "https://api.weather.gov/points/40.4442,-79.9396"; |
| 18 | +const fetchData = async <UWU extends ZodTypeAny>( |
| 19 | + url: string, |
| 20 | + schema: UWU, |
| 21 | + retriesLeft = 3 |
| 22 | +) => { |
| 23 | + try { |
| 24 | + const data = schema.parse(await (await fetch(url)).json()) as z.infer<UWU>; |
| 25 | + return data; |
| 26 | + } catch (e) { |
| 27 | + if (retriesLeft === 1) throw e; |
| 28 | + return fetchData(url, schema, retriesLeft - 1); |
| 29 | + } |
| 30 | +}; |
| 31 | +export async function getTodaysWeather() { |
| 32 | + const generalLocationData = await fetchData( |
| 33 | + rootApiURL, |
| 34 | + generalLocationSchema |
| 35 | + ); |
| 36 | + const forecastURL = generalLocationData.properties.forecast; |
| 37 | + const forecast = await fetchData(forecastURL, forecastSchema); |
| 38 | + let weatherToday: string | undefined, weatherTonight: string | undefined; |
| 39 | + for (const entry of forecast.properties.periods) { |
| 40 | + if (entry.name === "Today") { |
| 41 | + weatherToday = entry.detailedForecast; |
| 42 | + } |
| 43 | + if (entry.name === "Tonight") { |
| 44 | + weatherTonight = entry.detailedForecast; |
| 45 | + } |
| 46 | + } |
| 47 | + return `おはよう! Here's today's weather forecast for CMU, Pittsburgh\n\n*Today:* ${ |
| 48 | + weatherToday ?? "Unavailable" |
| 49 | + }\n\n*Tonight:* ${weatherTonight ?? "Unavailable"}`; |
| 50 | +} |
0 commit comments