Skip to main content
FastEdge applications can make outbound HTTP calls from inside the handler — reach out to any external service, transform the response, and return the result to the caller. This guide builds an application that fetches a list of users from a public REST API and returns the first five as JSON. It assumes the toolchain is already configured for the chosen language.

Handler

Create a new library crate or project, then write the handler for the chosen language.
Create a library crate and replace Cargo.toml:
cargo new --lib outbound-fetch
cd outbound-fetch
[package]
name = "outbound_fetch"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wstd = "0.6"
anyhow = "1"
serde_json = "1"
Replace src/lib.rs:
use anyhow::anyhow;
use wstd::http::body::Body;
use wstd::http::{Client, Request, Response};
use serde_json::{json, Value};

#[wstd::http_server]
async fn main(_request: Request<Body>) -> anyhow::Result<Response<Body>> {
    let upstream_req = Request::get("https://jsonplaceholder.typicode.com/users")
        .body(Body::empty())
        .map_err(|e| anyhow!("failed to build request: {e}"))?;

    let client = Client::new();
    let upstream_resp = client
        .send(upstream_req)
        .await
        .map_err(|e| anyhow!("upstream request failed: {e}"))?;

    let (_, mut body) = upstream_resp.into_parts();
    let body_bytes = body.contents().await?;

    let users: Value = serde_json::from_slice(body_bytes)?;
    let sliced = match users.as_array() {
        Some(arr) => Value::Array(arr.iter().take(5).cloned().collect()),
        None => Value::Array(vec![]),
    };
    let count = sliced.as_array().map(|a| a.len()).unwrap_or(0);

    Ok(Response::builder()
        .status(200)
        .header("content-type", "application/json")
        .body(Body::from(json!({ "count": count, "users": sliced }).to_string()))?)
}
Client::new() routes requests through the WASI outbound-http interface — the host runtime handles the actual network call. The await on client.send() is real async: the handler yields while the upstream request is in flight. The response body arrives as a stream; body.contents().await reads it fully into memory before parsing. Every ? propagates errors through anyhow::Result — FastEdge converts a handler returning Err into a 500 response, with the error message written to application logs.

Build

Compile the handler to a WebAssembly binary.
cargo build --release --target wasm32-wasip2
The binary is at ./target/wasm32-wasip2/release/outbound_fetch.wasm.

Deploy

The outbound call happens on every request, from every edge node that handles traffic for this app. For data that changes infrequently, storing the upstream response in a KV store eliminates per-request latency after the first fetch.