reflow_api_services 0.2.1

Generated API-service actor catalog for Reflow — thousands of actors across ~90 third-party services.
Documentation
#![allow(clippy::all, unused_imports, dead_code)]

//! Auto-generated API actors for HERE Maps
//!
//! Service: HERE Maps (here)
//! Location services and mapping platform
//!
//! Required env var: HERE_API_KEY (API key)
//!
//! Generated by api-schema-gen codegen — do not edit manually.

use crate::{Actor, ActorBehavior, ClientBuilderExt, Message, Port};
use anyhow::{Error, Result};
use reflow_actor::{message::EncodableValue, ActorContext};
use reflow_actor_macro::actor;
use serde_json::{json, Value};
use std::collections::HashMap;
use std::time::Duration;

const BASE_URL: &str = "https://router.hereapi.com/v8";
const ENV_KEY: &str = "HERE_API_KEY";

/// Apply authentication to the request builder.
fn apply_auth(
    config: &reflow_actor::ActorConfig,
    mut builder: reqwest::RequestBuilder,
) -> Result<reqwest::RequestBuilder> {
    let credential = config
        .get_config_or_env(ENV_KEY)
        .ok_or_else(|| anyhow::anyhow!("Missing env var: {}", ENV_KEY))?;
    builder = builder.query(&[("apiKey", &credential)]);
    Ok(builder)
}

/// read route via HERE Maps API
///
/// Method: GET /routes
#[actor(
    HereReadRouteActor,
    inports::<100>(transportMode, origin, destination, apiKey),
    outports::<50>(response, error),
    state(MemoryState)
)]
pub async fn here_read_route(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
    let inputs = context.get_payload();
    let actor_config = context.get_config();

    let endpoint = "/routes".to_string();

    let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);

    let client = reqwest::Client::builder()
        .timeout_compat(Duration::from_secs(30))
        .build()?;

    let mut builder = client.get(&url);
    builder = builder.header("Content-Type", "application/json");
    builder = apply_auth(actor_config, builder)?;

    let mut query_pairs: Vec<(&str, String)> = Vec::new();
    if let Some(val) = inputs.get("transportMode") {
        query_pairs.push(("transportMode", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("origin") {
        query_pairs.push(("origin", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("destination") {
        query_pairs.push(("destination", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("apiKey") {
        query_pairs.push(("apiKey", super::message_to_str(val)));
    }
    if !query_pairs.is_empty() {
        builder = builder.query(&query_pairs);
    }

    let mut output = HashMap::new();
    match builder.send().await {
        Ok(resp) => {
            let status = resp.status().as_u16();
            let headers: HashMap<String, String> = resp
                .headers()
                .iter()
                .filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
                .collect();
            let body_text = resp.text().await.unwrap_or_default();
            let body_value: Value =
                serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
            output.insert(
                "response".to_string(),
                Message::object(EncodableValue::from(json!({
                    "status": status,
                    "headers": headers,
                    "body": body_value,
                }))),
            );
        }
        Err(e) => {
            output.insert(
                "error".to_string(),
                Message::Error(format!("GET /routes failed: {}", e).into()),
            );
        }
    }

    Ok(output)
}

/// geocode address via HERE Maps API
///
/// Method: GET /geocode
#[actor(
    HereGeocodeAddressActor,
    inports::<100>(q, apiKey),
    outports::<50>(response, error),
    state(MemoryState)
)]
pub async fn here_geocode_address(
    context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
    let inputs = context.get_payload();
    let actor_config = context.get_config();

    let endpoint = "/geocode".to_string();

    let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);

    let client = reqwest::Client::builder()
        .timeout_compat(Duration::from_secs(30))
        .build()?;

    let mut builder = client.get(&url);
    builder = builder.header("Content-Type", "application/json");
    builder = apply_auth(actor_config, builder)?;

    let mut query_pairs: Vec<(&str, String)> = Vec::new();
    if let Some(val) = inputs.get("q") {
        query_pairs.push(("q", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("apiKey") {
        query_pairs.push(("apiKey", super::message_to_str(val)));
    }
    if !query_pairs.is_empty() {
        builder = builder.query(&query_pairs);
    }

    let mut output = HashMap::new();
    match builder.send().await {
        Ok(resp) => {
            let status = resp.status().as_u16();
            let headers: HashMap<String, String> = resp
                .headers()
                .iter()
                .filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
                .collect();
            let body_text = resp.text().await.unwrap_or_default();
            let body_value: Value =
                serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
            output.insert(
                "response".to_string(),
                Message::object(EncodableValue::from(json!({
                    "status": status,
                    "headers": headers,
                    "body": body_value,
                }))),
            );
        }
        Err(e) => {
            output.insert(
                "error".to_string(),
                Message::Error(format!("GET /geocode failed: {}", e).into()),
            );
        }
    }

    Ok(output)
}

/// Calculate a matrix of route summaries between many origins and destinations
///
/// Method: GET /matrix
#[actor(
    HereReadMatrixRouteActor,
    inports::<100>(apiKey, transportMode, origins, destinations, routingMode, departureTime, avoid_features, return_),
    outports::<50>(response, error),
    state(MemoryState)
)]
pub async fn here_read_matrix_route(
    context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
    let inputs = context.get_payload();
    let actor_config = context.get_config();

    let endpoint = "/matrix".to_string();

    let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);

    let client = reqwest::Client::builder()
        .timeout_compat(Duration::from_secs(30))
        .build()?;

    let mut builder = client.get(&url);
    builder = builder.header("Content-Type", "application/json");
    builder = apply_auth(actor_config, builder)?;

    let mut query_pairs: Vec<(&str, String)> = Vec::new();
    if let Some(val) = inputs.get("apiKey") {
        query_pairs.push(("apiKey", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("transportMode") {
        query_pairs.push(("transportMode", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("origins") {
        query_pairs.push(("origins", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("destinations") {
        query_pairs.push(("destinations", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("routingMode") {
        query_pairs.push(("routingMode", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("departureTime") {
        query_pairs.push(("departureTime", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("avoid_features") {
        query_pairs.push(("avoid[features]", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("return_") {
        query_pairs.push(("return", super::message_to_str(val)));
    }
    if !query_pairs.is_empty() {
        builder = builder.query(&query_pairs);
    }

    let mut output = HashMap::new();
    match builder.send().await {
        Ok(resp) => {
            let status = resp.status().as_u16();
            let headers: HashMap<String, String> = resp
                .headers()
                .iter()
                .filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
                .collect();
            let body_text = resp.text().await.unwrap_or_default();
            let body_value: Value =
                serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
            output.insert(
                "response".to_string(),
                Message::object(EncodableValue::from(json!({
                    "status": status,
                    "headers": headers,
                    "body": body_value,
                }))),
            );
        }
        Err(e) => {
            output.insert(
                "error".to_string(),
                Message::Error(format!("GET /matrix failed: {}", e).into()),
            );
        }
    }

    Ok(output)
}

/// Calculate an isoline (reachability area) from an origin within given constraints
///
/// Method: GET /isolines
#[actor(
    HereReadIsolineActor,
    inports::<100>(apiKey, transportMode, origin, destination, range_type, range_values, routingMode, departureTime, avoid_features, optimizeFor),
    outports::<50>(response, error),
    state(MemoryState)
)]
pub async fn here_read_isoline(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
    let inputs = context.get_payload();
    let actor_config = context.get_config();

    let endpoint = "/isolines".to_string();

    let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);

    let client = reqwest::Client::builder()
        .timeout_compat(Duration::from_secs(30))
        .build()?;

    let mut builder = client.get(&url);
    builder = builder.header("Content-Type", "application/json");
    builder = apply_auth(actor_config, builder)?;

    let mut query_pairs: Vec<(&str, String)> = Vec::new();
    if let Some(val) = inputs.get("apiKey") {
        query_pairs.push(("apiKey", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("transportMode") {
        query_pairs.push(("transportMode", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("origin") {
        query_pairs.push(("origin", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("destination") {
        query_pairs.push(("destination", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("range_type") {
        query_pairs.push(("range[type]", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("range_values") {
        query_pairs.push(("range[values]", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("routingMode") {
        query_pairs.push(("routingMode", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("departureTime") {
        query_pairs.push(("departureTime", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("avoid_features") {
        query_pairs.push(("avoid[features]", super::message_to_str(val)));
    }
    if let Some(val) = inputs.get("optimizeFor") {
        query_pairs.push(("optimizeFor", super::message_to_str(val)));
    }
    if !query_pairs.is_empty() {
        builder = builder.query(&query_pairs);
    }

    let mut output = HashMap::new();
    match builder.send().await {
        Ok(resp) => {
            let status = resp.status().as_u16();
            let headers: HashMap<String, String> = resp
                .headers()
                .iter()
                .filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
                .collect();
            let body_text = resp.text().await.unwrap_or_default();
            let body_value: Value =
                serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
            output.insert(
                "response".to_string(),
                Message::object(EncodableValue::from(json!({
                    "status": status,
                    "headers": headers,
                    "body": body_value,
                }))),
            );
        }
        Err(e) => {
            output.insert(
                "error".to_string(),
                Message::Error(format!("GET /isolines failed: {}", e).into()),
            );
        }
    }

    Ok(output)
}