JavaScript Mapping Library
Where I live could generously be called "warm", but is usually closer to the surface of the sun, especially in late summer. That’s why when the weather is not oppressively hot, I try my best to enjoy it. We’re mid-May now and honestly, this spring has been… pleasant. Suspiciously pleasant but I’ll take what I can get.
The last few weeks I’ve been telling myself that the weather must be a good bit cooler than last year, and I finally decided to do something about it. I worked with Claude and created a little web app that:
As I mentioned, I worked with Claude on this and let it design the layout and write the code initially. I was kinda impressed by one part – the mapWithConcurrency function that lets you pass an array of async function with a desired max number to run at once. It handles doing the batching and returning the final result. That makes the calls for the weather data a bit more gentle on the provider.
mapWithConcurrency
However – I noticed it was taking a long time to finish. In theory, I’m doing 7 times 5 (this week plus four previous years) of calls which is 35 which doesn’t seem like a lot, but I did some digging. Claude had used an endpoint that was a bit old. Doing some more research I switched to the proper endpoint… which didn’t support CORS.
Oh no!
Oh – actually – I just moved to this to val.town and built a quick server side proxy. It takes in the same arguments that’s send to my client side code (lat, lng, and a timestamp), and passes it to the historical Pirate Weather endpoint. So here’s the frontend code – again – this is being driven by a concurrency function:
async function fetchDayTemperatures(lat, lng, unixSeconds) { let req = await fetch(PIRATE_WEATHER_API_BASE, { method: "POST", body: JSON.stringify({ lat, lng, unixSeconds, }), }); return await req.json(); }
And here’s the backend code:
export default async function (req: Request): Promise<Response> { const body = await req.json(); const key = Deno.env.get("PIRATE"); const url = new URL( `https://timemachine.pirateweather.net/forecast/$ {key}/$ {body.lat},$ {body.lng},$ {body.unixSeconds}`, ); url.searchParams.set("units", "us"); url.searchParams.set("exclude", "minutely,hourly,alerts,flags"); const response = await fetch(url); const payload = await response.json(); if (!response.ok) { throw new Error(payload.error || "Weather lookup failed."); } const day = payload.daily?.data?.[0]; if (!day) { throw new Error("Weather data did not include a daily summary."); } return Response.json({ timezone: payload.timezone, high: day.temperatureMax, low: day.temperatureMin, }); }
I barely modified this from the original client side code – only switching to an environment variable for the API (their API is free, but I might as well) and returning a proper Response object.
Response
Here’s a screenshot of it in action:
You can try this yourself here: https://weathercomparison.val.run/. If you want to see the code, and possibly fork the val, you can do so here: https://www.val.town/x/raymondcamden/weather-comparison
No. I was wrong. Last year was cooler than this year, but the three years before that were all higher, with 2022 being pure hell. I remember that year seeing the city working on a road that had literally buckled because of heat.
Photo by Peter Albanese on Unsplash
Raymond Camden
You must be logged in to post a comment.
This site uses Akismet to reduce spam. Learn how your comment data is processed.