A developer-friendly SDK for the National Weather Service API. Forecasts, alerts, observations, and glossary with clean Kotlin types and coroutine-first design.
Four complete service layers covering all major NWS endpoints, with clean models and structured error handling.
Daily and hourly forecasts by coordinates, gridpoint, or zone. Automatic lat/lon to gridpoint resolution.
Active weather alerts filtered by state, zone, or ID. Typed severity, urgency, and certainty enums.
Current conditions from weather stations. Temperature, humidity, wind, pressure, visibility, and more.
All service methods are suspend functions. Clean, non-blocking async with Retrofit's native support.
Typed exception hierarchy for API errors, rate limits, network failures, and parse errors.
Built-in structured logging via SLF4J. Debug, info, and error logs across all services. Plug any backend.
Add the dependency, create the SDK, start fetching weather data. No API keys, no complex setup.
// Add to your dependencies block implementation("dev.abid.noaa.weather:noaa-weather-sdk-kotlin:1.0.0") // SLF4J backend of your choice (e.g., Logback) runtimeOnly("ch.qos.logback:logback-classic:1.5.6")
import dev.abid.noaa.weather.sdk.NoaaWeatherSdk import kotlinx.coroutines.runBlocking fun main() = runBlocking { val sdk = NoaaWeatherSdk.builder() .userAgent("my-weather-app, contact@example.com") .build() val forecast = sdk.forecasts.getDailyForecast(39.7456, -104.9984) forecast.periods.forEach { period -> println("${period.name}: ${period.temperature}${period.temperatureUnit}") } }
Everything you need to integrate weather data into your Kotlin application.
The SDK is configured via the builder pattern. The userAgent field is required by the NWS API — use the format "app-name, contact-info".
userAgentbaseUrlhttps://api.weather.gov. Override for testing.connectTimeoutreadTimeoutenableLoggingFetch daily and hourly forecasts. Methods that take coordinates automatically resolve to the nearest gridpoint via the NWS /points endpoint.
| Method | Returns | Description |
|---|---|---|
getDailyForecast(lat, lon) | DailyForecast | Daily forecast for coordinates. Auto-resolves gridpoint. |
getHourlyForecast(lat, lon) | List<HourlyForecast> | Hourly forecast for coordinates. |
getGridpointForecast(wfo, x, y) | GridpointForecast | Daily forecast by gridpoint (skip location lookup). |
getGridpointHourly(wfo, x, y) | List<HourlyForecast> | Hourly forecast by gridpoint. |
getZoneForecast(zoneId) | ZoneForecast | Forecast by NWS zone ID (e.g., "COZ001"). |
ForecastPeriodname, startTime, endTime, temperature, temperatureUnit, windSpeed, windDirection, shortForecast, detailedForecast, icon
HourlyForecasttime, temperature, dewpoint, relativeHumidity, probabilityOfPrecipitation, windChill, heatIndex
DailyForecastperiods: List<ForecastPeriod>, generatedAt: Instant
GridPointwfo: String (e.g., "BOU"), gridX: Int, gridY: Int
Query active weather alerts. Alerts include typed enums for severity, urgency, and certainty — no string parsing needed.
| Method | Returns | Description |
|---|---|---|
getActiveAlerts() | List<Alert> | All currently active alerts. |
getAlertsByArea(stateCode) | List<Alert> | Alerts for a 2-letter US state code (e.g., "CO"). |
getAlertsByZone(zoneId) | List<Alert> | Alerts for an NWS zone (e.g., "COZ001"). |
getAlert(id) | Alert | Single alert by its NWS identifier. |
Alertid, event, headline, description, instruction, area, affectedZones, effective, expires, sender
AlertSeverityEXTREME, SEVERE, MODERATE, MINOR, UNKNOWN
AlertUrgencyIMMEDIATE, EXPECTED, FUTURE, PAST, UNKNOWN
AlertCertaintyOBSERVED, LIKELY, POSSIBLE, UNLIKELY, UNKNOWN
Access current conditions from NWS observation stations. Find stations by location, then retrieve the latest readings.
| Method | Returns | Description |
|---|---|---|
getNearbyStations(lat, lon) | List<Station> | Observation stations near the given coordinates. |
getLatestObservation(stationId) | Observation | Most recent reading from a station (e.g., "KDEN"). |
getObservations(stationId) | List<Observation> | Historical observations from a station. |
Stationid, name, coordinates: GeoPoint, elevation
Observationtemperature, dewpoint, windSpeed, windDirection, windGust, barometricPressure, visibility, relativeHumidity, precipitationLastHour, weatherDescription
NWS term definitions and weather icon metadata. Useful for building educational or reference interfaces.
| Method | Returns | Description |
|---|---|---|
getGlossaryTerms() | List<GlossaryTerm> | |
getIcons() | List<IconInfo> | Weather icon metadata from the NWS icon library. |
The SDK uses SLF4J for structured logging. Add your preferred backend (Logback, Log4j2, SLF4J-Simple) and everything lights up automatically. No implementation binding is included — that's the consumer's choice.
| Component | DEBUG | INFO | ERROR |
|---|---|---|---|
| Interceptor | Every request URL + response code | — | Rate limits (429), API errors |
| ForecastService | Lat/lon params, gridpoint params | Resolved gridpoint, period count | — |
| AlertService | State/zone/id params | Alert count, event details | — |
| ObservationService | Station ID, coordinates | Station count, temp summary | — |
| GlossaryService | Endpoint being called | Term/icon count | Parse failures (with stack trace) |
<!-- Enable SDK debug logs --> <logger name="dev.abid.noaa.weather.sdk" level="DEBUG"/>
Each service is a property on the SDK instance. All methods are coroutine suspend functions.
// Hourly forecast by coordinates val hourly = sdk.forecasts .getHourlyForecast(39.7456, -104.9984) // Direct gridpoint (skip lookup) val grid = sdk.forecasts .getGridpointForecast("BOU", 65, 61) // Zone-based forecast val zone = sdk.forecasts .getZoneForecast("COZ001")
// All active alerts val all = sdk.alerts.getActiveAlerts() // By state (2-letter code) val co = sdk.alerts .getAlertsByArea("CO") // Single alert val alert = sdk.alerts .getAlert("urn:oid:2.49.0...") println(alert.severity) // EXTREME
// Find nearby stations val stations = sdk.observations .getNearbyStations(39.86, -104.67) // Latest reading val obs = sdk.observations .getLatestObservation("KDEN") println("Temp: ${obs.temperature}") println("Wind: ${obs.windSpeed}")
val sdk = NoaaWeatherSdk.builder() .userAgent("my-app, me@example.com") .baseUrl("http://localhost:8080") .connectTimeout(5.seconds) .readTimeout(15.seconds) .enableLogging(true) .build()
All errors are subclasses of NoaaWeatherException, making catch blocks clean and specific.
| Exception | When | Key Properties |
|---|---|---|
NoaaApiException | NWS API returned a non-2xx response | statusCode, errorBody |
NoaaRateLimitException | HTTP 429 — too many requests | retryAfter |
NoaaNetworkException | Network failure (timeout, DNS, etc.) | cause (IOException) |
NoaaParseException | Response body could not be parsed | rawBody |
try { val forecast = sdk.forecasts.getDailyForecast(39.7456, -104.9984) } catch (e: NoaaRateLimitException) { println("Rate limited. Retry after: ${e.retryAfter}") } catch (e: NoaaApiException) { println("API error ${e.statusCode}: ${e.message}") } catch (e: NoaaNetworkException) { println("Network error: ${e.message}") } catch (e: NoaaWeatherException) { println("SDK error: ${e.message}") }
Start fetching forecasts, alerts, and observations in your Kotlin app today. Free, open-source, no API key needed.
Get Started Now