nea-rs 0.1.1

A type-safe, sans-IO Rust client for Singapore NEA real-time weather and environmental APIs.
Documentation

Install

Add nea-rs and the satay-reqwest adapter (plus reqwest and tokio for the async example below):

cargo add nea-rs satay-reqwest reqwest
cargo add tokio --features macros,rt-multi-thread

Or add the same dependencies to Cargo.toml:

[dependencies]
nea-rs = "0.1"
satay-reqwest = "0.1"
reqwest = "0.13.3"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Reqwest 0.13 uses rustls by default, so HTTPS works without an extra TLS feature. If your app needs blocking clients, proxies, or other transport options, keep a direct reqwest dependency and enable features there. See Using other client backends and the Satay transport docs.

Example

Fetch the latest air temperature readings with reqwest and satay-reqwest:

use nea_rs::Api;
use satay_reqwest::ReqwestActionExt;
use satay_reqwest::reqwest::Client;
use std::env;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let client = Client::new();
    let mut api = Api::new();
    if let Ok(key) = env::var("X_API_KEY") {
        api = api.x_api_key(key);
    }
    let response = api.air_temperature().send_with(&client).await?;
    println!("{response:#?}");
    Ok(())
}

From this repo, run the same logic as a binary example:

cargo run --example air_temperature

Optional: set X_API_KEY to your data.gov.sg API key. More runnable examples live under examples/.

Using other client backends

nea-rs is sans-IO: generated actions build http::Request<Vec<u8>> values and decode responses without performing IO. Pick the HTTP client that fits your application, or use the same boundary directly in tests, WASM, or custom transports.

See satay-rs for more details

ureq

[dependencies]
nea-rs = "0.1"
satay-ureq = "0.1"
ureq = "3"
use nea_rs::Api;
use satay_ureq::UreqActionExt;
use satay_ureq::ureq;
use std::env;
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let mut api = Api::new();
    if let Ok(key) = env::var("X_API_KEY") {
        api = api.x_api_key(key);
    }

    let agent: ureq::Agent = ureq::Agent::config_builder()
        .http_status_as_error(false)
        .build()
        .into();

    let response = api.air_temperature().send_with(&agent)?;
    println!("{response:#?}");
    Ok(())
}

Configure the agent with http_status_as_error(false) so Satay can decode typed non-2xx responses instead of ureq treating them as transport errors.

reqwest (blocking)

Enable the blocking feature on both crates when you want a synchronous reqwest client:

[dependencies]
nea-rs = "0.1"
satay-reqwest = { version = "0.1", features = ["blocking"] }
reqwest = { version = "0.13.3", features = ["blocking"] }
use nea_rs::Api;
use satay_reqwest::ReqwestBlockingActionExt;
use satay_reqwest::reqwest::blocking;
use std::env;
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let mut api = Api::new();
    if let Ok(key) = env::var("X_API_KEY") {
        api = api.x_api_key(key);
    }
    let response = api
        .air_temperature()
        .send_with(&blocking::Client::new())?;
    println!("{response:#?}");
    Ok(())
}

For more transport patterns (including WebSocket and custom adapters), see the Satay transport docs and the examples under satay-rs/examples/.

More examples

If you would like to see more examples, take a look at the examples folder

Security

Please see SECURITY.md for vulnerability reporting.

License

Licensed under either of:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.