# How TREK's Weather Forecast Integration with Open-Meteo API Works

> Learn how TREK integrates weather forecasts using the Open-Meteo API. Discover coordinate validation, caching, and WMO code translation for accurate weather data.

- Repository: [Maurice/TREK](https://github.com/mauriceboe/TREK)
- Tags: how-to-guide
- Published: 2026-07-11

---

**TREK retrieves weather data through a thin service layer that validates coordinates against Zod schemas, caches results in memory with TTL-based expiration, and routes requests to Open-Meteo's forecast or archive endpoints based on date ranges, translating WMO weather codes into localized descriptions.**

TREK is an open-source application that provides weather forecasts without requiring API keys by leveraging the free Open-Meteo service. The integration is implemented in TypeScript and handles everything from request validation to intelligent endpoint selection and response caching. This article examines the exact implementation found in the `mauriceboe/TREK` repository.

## Request Validation and Schema Design

The integration begins with strict parameter validation using Zod. Incoming queries must satisfy the schemas defined in [`shared/src/weather/weather.schema.ts`](https://github.com/mauriceboe/TREK/blob/main/shared/src/weather/weather.schema.ts), which enforce `lat` and `lng` as required strings while making `date` optional. When omitted, the system returns current weather conditions; when provided, it triggers forecast or archive logic depending on the date's temporal distance.

The `lang` parameter defaults to German (`de`) and drives the localization of weather descriptions later in the pipeline.

## Intelligent Caching Strategy

Before initiating network requests, the service checks an in-memory `Map` cache using a deterministic key format computed by the `cacheKey` function.

```typescript
// From server/src/services/weatherService.ts
const cacheKey = (lat: string, lng: string, date?: string) => 
  `${lat}_${lng}_${date || 'current'}`;

```

The cache implements **time-to-live (TTL)** policies differentiated by data type:
- **Current conditions**: 15 minutes
- **Short-term forecasts** (up to 16 days): 1 hour  
- **Archive/climate data**: 24 hours

A concurrency guard prevents duplicate fetches for identical in-flight requests. The `inFlight` Map stores pending promises keyed by the same cache key, ensuring that simultaneous requests for the same coordinates and date share a single network call.

## Open-Meteo Endpoint Selection Logic

The service determines which Open-Meteo endpoint to query based on the requested date's relationship to the current time. This logic resides in [`server/src/services/weatherService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/weatherService.ts) between lines 58-97.

**Current Weather** (no date parameter):
- Endpoint: `api.open-meteo.com/v1/forecast`
- Parameters: `current=` variables for immediate conditions

**Forecast Range** (-1 to +16 days):
- Endpoint: `api.open-meteo.com/v1/forecast`
- Parameters: `daily=` arrays with `forecast_days=16`

**Historical Data** (< -1 day):
- Endpoint: `archive-api.open-meteo.com/v1/archive`
- Returns observed data for the specific calendar day

**Climate Fallback** (> +16 days):
- Endpoint: `archive-api.open-meteo.com/v1/archive`
- Strategy: Queries a 5-day window around the same calendar day from the previous year to provide climate estimates

All requests include `timezone=auto` to ensure localized time formatting in the response.

## Data Transformation and WMO Code Mapping

Open-Meteo returns numeric **WMO weather codes** that require translation into human-readable strings. TREK maintains two lookup tables in [`weatherService.ts`](https://github.com/mauriceboe/TREK/blob/main/weatherService.ts):

- **`WMO_MAP`**: Provides short labels (e.g., "Partly cloudy")
- **`WMO_DESCRIPTION_EN`** and **`WMO_DESCRIPTION_DE`**: Offer detailed explanations

The service constructs a `WeatherResult` object containing:
- Temperature aggregates (average, max, min)
- Derived `main` and `description` fields from WMO lookups
- Sunrise and sunset times
- Precipitation sums and maximum wind speeds
- Optional `hourly` arrays for detailed forecasts

## Error Handling and Security

Network requests use Node's native `fetch` implementation. The service validates HTTP status codes and checks for `error` fields in the JSON payload, throwing a custom `ApiError` class when Open-Meteo returns invalid data.

Security constraints are enforced in [`server/src/middleware/globalMiddleware.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/middleware/globalMiddleware.ts), where the Content Security Policy (CSP) explicitly whitelists `https://open-meteo.com`, `https://api.open-meteo.com`, and the archive subdomain in the `connect-src` directive. This authorization allows browser clients to reach the API while maintaining strict security boundaries.

## Usage Examples

### HTTP API Endpoint

Request current weather for Berlin:

```bash
GET /api/weather?lat=52.5&lng=13.4&lang=en

```

Request a specific date forecast:

```bash
GET /api/weather?lat=52.5&lng=13.4&date=2025-08-01&lang=en

```

Example response structure:

```json
{
  "temp": 22,
  "temp_max": 25,
  "temp_min": 18,
  "main": "Partly cloudy",
  "description": "Partly cloudy",
  "type": "forecast",
  "sunrise": "05:12",
  "sunset": "21:03",
  "precipitation_sum": 0,
  "wind_max": 12
}

```

### Direct Service Integration

Import and call the service functions directly from your TypeScript code:

```typescript
import { getWeather, getDetailedWeather } from './services/weatherService';

// Current conditions
const current = await getWeather('52.5', '13.4', undefined, 'de');

// 16-day forecast window
const forecast = await getWeather('52.5', '13.4', '2025-08-01', 'en');

// Hourly detail (uses archive API for dates beyond 16 days)
const detailed = await getDetailedWeather('52.5', '13.4', '2026-09-15', 'en');

```

## Summary

TREK's Open-Meteo integration demonstrates a production-ready pattern for consuming third-party weather APIs:

- **Validation layer**: Zod schemas in [`weather.schema.ts`](https://github.com/mauriceboe/TREK/blob/main/weather.schema.ts) enforce type safety on inputs
- **Smart routing**: Automatic selection between forecast and archive endpoints based on temporal distance
- **Performance optimization**: In-memory caching with differentiated TTLs and request deduplication via `inFlight` promises
- **Localization**: WMO code translation supporting English and German descriptions
- **Security**: CSP whitelisting in [`globalMiddleware.ts`](https://github.com/mauriceboe/TREK/blob/main/globalMiddleware.ts) restricts outbound connections to authorized domains

## Frequently Asked Questions

### Does TREK require an API key for Open-Meteo?

No. TREK leverages Open-Meteo's free public API endpoints that do not require authentication. The service constructs URLs directly to `api.open-meteo.com` and `archive-api.open-meteo.com` without inserting API keys, making the integration immediately usable without configuration.

### How does TREK handle dates beyond the 16-day forecast limit?

When a user requests a date more than 16 days in the future, TREK falls back to the archive API and retrieves climate data from the previous year. Specifically, it queries a 5-day window around the same calendar day from historical records, providing representative weather patterns rather than specific forecasts.

### What happens when multiple users request the same weather data simultaneously?

The `inFlight` Map in [`weatherService.ts`](https://github.com/mauriceboe/TREK/blob/main/weatherService.ts) stores pending promises for ongoing requests. If a second request arrives with identical parameters (latitude, longitude, date, and language) while the first is still fetching, the service returns the same promise to both callers. This prevents duplicate network requests and reduces load on the Open-Meteo servers.

### How are weather condition codes translated into text?

Open-Meteo returns numeric WMO standard codes. TREK maps these to human-readable strings using lookup tables defined in [`weatherService.ts`](https://github.com/mauriceboe/TREK/blob/main/weatherService.ts). The `WMO_MAP` provides short labels like "Partly cloudy," while `WMO_DESCRIPTION_EN` and `WMO_DESCRIPTION_DE` contain longer explanations, with the appropriate language selected based on the `lang` parameter.