/spin-rust-sdk

Primary LanguageRustApache License 2.0Apache-2.0

The Spin Rust SDK

The Spin Rust SDK makes it easy to build Spin components in Rust.

Fermyon Developer Home

This README file provides a few examples, such as writing Spin HTTP components in Rust and making outbound HTTP requests. For comprehensive information, visit the official Fermyon Developer Home. This resource includes a page on installing Spin, a quickstart guide, and a language support overview page. The latter lists all of Spin's features—including key-value storage, SQLite, MySQL, Redis, Serverless AI, etc.—and their implementation in specific languages such as Rust, TS/JS, Python, and TinyGo.

Writing Spin HTTP Components in Rust

This library simplifies writing Spin HTTP components. Below is an example of such a component:

// lib.rs
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;

/// A simple Spin HTTP component.
#[http_component]
fn handle_hello_world(req: Request) -> anyhow::Result<impl IntoResponse> {
    println!("Handling request to {:?}", req.header("spin-full-url"));
    Ok(Response::builder()
        .status(200)
        .header("content-type", "text/plain")
        .body("Hello, Fermyon")
        .build())
}

The important things to note about the function above are:

  • the spin_sdk::http_component macro marks the function as the entry point for the Spin component,
  • in the function signature (fn handle_hello_world(req: Request) -> anyhow::Result<impl IntoResponse>), req can be any number of types, including the built-in Request type or the http::Request type from the popular http crate
  • in the function signature, the response type can be anything that implements IntoResponse meaning the return type can any number of things including anyhow::Result<impl IntoResponse> (as shown above), impl IntoResponse, Response, anyhow::Result<Response>, or even the http::Response type from the http crate.
    • Note: Using the http crate will require you to add it to your Cargo.toml manifest (i.e., cargo add http).

Making Outbound HTTP Requests

Let's see an example where the component makes an outbound HTTP request to a server, modifies the result, and then returns it:

use spin_sdk::{
    http::{IntoResponse, Request, Method, Response},
    http_component,
};

#[http_component]
async fn handle_hello_world(_req: Request) -> Result<impl IntoResponse> {
    // Create the outbound request object
    let req = Request::builder()
        .method(Method::Get)
        .uri("https://random-data-api.fermyon.app/animals/json")
        .build();

    // Send the request and await the response
    let res: Response = spin_sdk::http::send(req).await?;

    println!("{:?}", res);  // log the response
    Ok(res)
}

For the component above to be allowed to make the outbound HTTP request, the destination host must be declared, using the allowed_outbound_hosts configuration, in the Spin application's manifest (the spin.toml file):

spin_manifest_version = 2

[application]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <your-name@example.com>"]
description = "An example application"

[[trigger.http]]
route = "/..."
component = "hello-world"

[component.hello-world]
source = "target/wasm32-wasi/release/hello_world.wasm"
allowed_outbound_hosts = ["https://random-data-api.fermyon.app"]
[component.hello-world.build]
command = "cargo build --target wasm32-wasi --release"
watch = ["src/**/*.rs", "Cargo.toml"]

Building and Running the Spin Application

Spin build can be used to build all components defined in the Spin manifest file at the same time, and also has a flag that starts the application after finishing the compilation, spin build --up:

$ spin build --up
Building component hello-world with `cargo build --target wasm32-wasi --release`
    Finished release [optimized] target(s) in 0.12s
Finished building all Spin components
Logging component stdio to ".spin/logs/"

Serving http://127.0.0.1:3000
Available Routes:
  hello-world: http://127.0.0.1:3000 (wildcard)

Once our application is running, we can make a request (by visiting http://localhost:3000/ in a web browser) or using curl as shown below:

$ curl -i localhost:3000
HTTP/1.1 200 OK
content-length: 77
content-type: application/json

{"timestamp":1702599575198,"fact":"Sharks lay the biggest eggs in the world"}