To provide real-time weather data, you need to handle API integration, error handling and automatic scaling. With Vercel functions and Express, you can build a production-ready weather API in minutes.
In this tutorial, you will build and deploy a weather API route using the Open-Meteo API that:
- Accepts a city name and geocodes it to coordinates
- Fetches current weather data from the Open-Meteo API
- Returns temperature, humidity, wind speed, and other weather metrics with optional metric/imperial unit conversion
- Node.js and pnpm installed locally
- A Vercel account
- Basic understanding of Express and async/await in TypeScript
Start with the Express starter template. Once your the project is deployed on Vercel, clone the repository locally.
You can also create the project locally using the Vercel CLI with the following command
vc init express
Add the weather endpoint after your existing routes:
app.get('/api/weather/:city', async (req, res) => { try { const city = req.params.city const units = req.query.units as string | undefined // Normalize units parameter const normalizedUnits = units === 'imperial' ? 'imperial' : 'metric' // Step 1: Geocode city to get coordinates const geoParams = new URLSearchParams({ name: city, count: '1', language: 'en', format: 'json' }) const geoResponse = await fetch(`https://geocoding-api.open-meteo.com/v1/search?${geoParams}`) if (!geoResponse.ok) { return res.status(geoResponse.status).json({ error: 'Failed to fetch geocoding data' }) } const geoData = await geoResponse.json() if (!geoData.results || geoData.results.length === 0) { return res.status(404).json({ error: `City '${city}' not found` }) } const location = geoData.results[0] const { name, country, latitude, longitude } = location // Step 2: Fetch current weather data const weatherParams: Record<string, string> = { latitude: latitude.toString(), longitude: longitude.toString(), current: 'temperature_2m,relative_humidity_2m,apparent_temperature,wind_speed_10m', timezone: 'auto' } // Add unit parameters for imperial if needed if (units === 'imperial') { weatherParams.temperature_unit = 'fahrenheit' weatherParams.wind_speed_unit = 'mph' } const weatherUrlParams = new URLSearchParams(weatherParams) const weatherResponse = await fetch(`https://api.open-meteo.com/v1/forecast?${weatherUrlParams}`) if (!weatherResponse.ok) { return res.status(weatherResponse.status).json({ error: 'Failed to fetch weather data' }) } const weatherData = await weatherResponse.json() // Return structured weather data res.json({ city: name, country, latitude, longitude, units: normalizedUnits, current: weatherData.current }) } catch (error) { console.error('Weather API error:', error) res.status(500).json({ error: 'Failed to fetch weather data', message: error instanceof Error ? error.message : 'Unknown error' }) }})
Install the dependencies and launch the application in dev mode:
pnpm installvercel dev
Use curl
to test the API route:
# Test with default metric unitscurl http://localhost:3000/api/weather/london
# Test with imperial unitscurl "http://localhost:3000/api/weather/san%20francisco?units=imperial"
- Push the changes to your remote repository or run the
vercel
cli command - Vercel will create a new preview deployment for your to test
- Merge to main branch to deploy to Production
In this tutorial, you’ve built a real-time weather API using Express on Vercel.
You learned to:
- Structure a dynamic API route and integrate external APIs
- Deploy the app to Vercel as a function for automatic scaling
For a production application, make sure that you use a weather API that will not be rate limited based on the amount of traffic that you are expecting.