Skip to content

vgg-dev/outdoor-activity-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Outdoor Activity API

release license node render checks

US-focused backend API for finding the best times to get outside.

It combines forecast, alerts, air quality, UV, astronomy, and aviation weather data into activity-aware recommendation windows for:

  • bike
  • hike
  • fishing
  • astronomy
  • drone

Why This Exists

Outdoor decision-making is scattered across multiple sources: forecast, alerts, air quality, UV, moonlight, and in some cases aviation visibility. This API pulls those signals into one place and turns them into recommendation windows that are easier for a mobile app to explain and trust.

What The API Produces

The API is designed to turn multiple upstream data sources into one recommendation payload with:

  • normalized hourly weather, AQI, UV, astronomy, and aviation context
  • activity-aware hourly scores
  • top recommendation windows with plain-language reasons
  • safety overlays such as severe alerts and aviation visibility context

Architecture

flowchart LR
  Client["Mobile / Web Client"] --> API["Outdoor Activity API"]
  API --> NWS["Weather.gov\nforecast, alerts, grid data"]
  API --> AirNow["AirNow\nAQI"]
  API --> EPA["EPA UV\nhourly UV"]
  API --> USNO["USNO\nmoon phase + illumination"]
  API --> AWC["Aviation Weather\nMETAR + TAF"]
  API --> Geo["Zippopotam.us / Census\nlocation search + reverse geocode"]
  API --> Score["Scoring Engine\nwindows, safety, comfort"]
  Score --> Client
Loading

Highlights

  • Hour-by-hour scoring for the next 24 hours
  • Top recommendation windows instead of single "best hours"
  • Weather.gov alert awareness with high-risk filtering
  • Structured wind gust and feels-like temperature enrichment from Weather.gov grid data
  • AirNow AQI integration
  • EPA UV integration
  • USNO moon illumination and phase enrichment for astronomy
  • Aviation Weather current METAR visibility plus nearest-airport TAF forecast context for drone and astronomy
  • ZIP, city/state, and coordinate-based location workflows
  • Render-friendly deployment and production hardening

Current Capabilities

  • ZIP lookup
  • City/state lookup
  • GPS-style coordinate requests
  • Weather.gov forecast and alerts
  • AirNow AQI
  • EPA UV
  • Weather.gov wind gusts
  • Weather.gov feels-like temperature
  • USNO moon illumination and phase
  • Aviation Weather METAR visibility
  • Aviation Weather TAF forecast summary
  • Activity-aware scoring for bike, hike, fishing, astronomy, and drone

Data Sources

API Overview

GET /health

Basic health check.

Example:

curl http://localhost:3000/health

GET /location-search?city=Gaithersburg&state=MD

Resolves a US city/state pair to coordinates and, when available, ZIP.

Example response:

{
  "city": "Gaithersburg",
  "state": "MD",
  "displayName": "Gaithersburg, MD",
  "lat": 39.1419,
  "lon": -77.189,
  "zip": "20877"
}

GET /recommendations

Returns scored hourly forecast data plus top recommendation windows.

Example:

curl "http://localhost:3000/recommendations?lat=39.1419&lon=-77.189&zip=20877&city=Gaithersburg&state=MD&activity=bike"

Response includes:

  • location
  • warnings
  • airQuality
  • uv
  • astronomy (for astronomy activity)
  • aviation (current METAR plus forecast TAF data for drone and astronomy)
  • recommendations
  • hourly

Example response excerpt:

{
  "location": {
    "lat": 39.1419,
    "lon": -77.189,
    "zip": "20877",
    "displayName": "Gaithersburg, MD"
  },
  "activity": "bike",
  "warnings": {
    "hasAnyAlert": false,
    "hasSevereAlert": false,
    "hasHighRiskAlert": false
  },
  "airQuality": {
    "source": "airnow",
    "currentAqi": 36
  },
  "uv": {
    "source": "epa-uv"
  },
  "aviation": {
    "current": {
      "source": "aviationweather",
      "visibilityMiles": 10,
      "flightCategory": "VFR"
    },
    "forecast": {
      "source": "aviationweather",
      "issuedAt": "2026-03-24T15:02:00.000Z",
      "periods": [
        {
          "startTime": "2026-03-24T15:00:00.000Z",
          "endTime": "2026-03-24T20:00:00.000Z",
          "visibilityMiles": 6,
          "ceilingFeet": null,
          "flightCategory": "VFR"
        }
      ]
    }
  },
  "recommendations": [
    {
      "start": "2026-03-18T14:00:00-04:00",
      "end": "2026-03-18T16:00:00-04:00",
      "hours": 2,
      "averageScore": 84,
      "why": [
        "Cooler than preferred",
        "Wind conditions look good",
        "Low rain chance"
      ]
    }
  ]
}

Activity Examples

Bike

  • Prefers comfortable temperatures, manageable wind, good AQI, and daylight
  • Uses structured gusts and feels-like temperature to avoid “looks nice on paper” false positives

Drone

  • Uses stricter wind and gust thresholds
  • Surfaces aviation visibility and TAF forecast context
  • Treats severe alerts and unsafe wind as hard stops

Astronomy

  • Prefers nighttime and clearer skies
  • Uses moon phase and illumination from USNO
  • Adds aviation visibility as a helpful haze/clarity signal

Quick Start

1. Install

npm install

2. Configure environment

Copy .env.example to .env and fill in values as needed.

PORT=3000
NODE_ENV=production
WEATHER_GOV_UA=OutdoorTimeFinder/1.0 (your-email@example.com)
AIRNOW_API_KEY=your_airnow_api_key_here
CORS_ORIGINS=https://your-frontend.example.com
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=60
UPSTREAM_TIMEOUT_MS=8000
RECOMMENDATION_CACHE_TTL_MS=300000

Notes:

  • AIRNOW_API_KEY is optional for local development, but AQI will be null without it.
  • WEATHER_GOV_UA should include a real contact email in production.
  • CORS_ORIGINS accepts a comma-separated allowlist of browser origins.

3. Run

npm start

4. Smoke test

curl http://localhost:3000/health
curl "http://localhost:3000/location-search?city=Gaithersburg&state=MD"
curl "http://localhost:3000/recommendations?lat=39.1419&lon=-77.189&zip=20877&city=Gaithersburg&state=MD&activity=bike"

Development

Run a quick code sanity check:

npm test

Current test coverage is lightweight and focused on syntax/entrypoint validation. Functional API smoke tests are still manual.

Regression tests currently cover:

  • UV hourly matching without timezone drift
  • multi-word city/state parsing
  • cache key separation for explicit place requests
  • structured Weather.gov gust parsing
  • structured Weather.gov apparent temperature parsing
  • USNO moon illumination parsing
  • Aviation Weather visibility parsing
  • Aviation Weather TAF category and ceiling derivation
  • cache behavior for UV edge cases

API Behavior Notes

  • UV may be null at night after the upstream hourly UV series ends; this is normal and should be treated as no UV risk, not a daytime failure.
  • Aviation data is advisory and best-effort. Nearby stations sometimes have incomplete observations, so the API falls back to other nearby METAR stations when needed.
  • TAF data is airport-based forecast context, not a hyperlocal surface forecast for every coordinate.
  • Astronomy and aviation enrichments are scoped to the activities that actually benefit from them, rather than affecting every recommendation equally.

Deploying to Render

This repo includes render.yaml, but the easiest path for most users is a standard Render Web Service.

Option 1: Render Web Service

Use:

  • Build command: npm install
  • Start command: npm start
  • Health check path: /health

Recommended environment variables:

NODE_ENV=production
WEATHER_GOV_UA=OutdoorTimeFinder/1.0 (your-email@example.com)
AIRNOW_API_KEY=your_airnow_api_key_here
CORS_ORIGINS=https://your-frontend.example.com
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=60
UPSTREAM_TIMEOUT_MS=8000
RECOMMENDATION_CACHE_TTL_MS=300000

Option 2: Render Blueprint

If your Render plan supports Blueprints, this repo is already set up for that via render.yaml.

Production Hardening Included

  • proxy-aware request handling
  • configurable CORS allowlist
  • basic security headers
  • per-IP rate limiting
  • upstream timeouts
  • short-lived response caching
  • safer external API error handling
  • backend-only integration for providers that do not permit browser CORS

Roadmap

  • Visibility-aware scoring for drone and astronomy
  • Richer astronomy response examples in the docs
  • Broader API regression coverage beyond parser-focused tests
  • Optional persistent caching layer for production deployments

Project Structure

src/
  config.js
  scoring.js
  server.js
  services/
    airnow.js
    aviationWeather.js
    geocode.js
    usno.js
    uv.js
    weatherGov.js

License

ISC. See LICENSE.

About

Backend API for outdoor activity timing recommendations

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors