Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
446 changes: 372 additions & 74 deletions Cargo.lock

Large diffs are not rendered by default.

22 changes: 17 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,24 @@ The Spin Rust SDK makes it easy to build Spin components in Rust.
name = "spin_sdk"

[dependencies]
anyhow = "1"
anyhow = { workspace = true }
async-trait = "0.1.74"
chrono = "0.4.38"
form_urlencoded = "1.0"
postgres_range = { version = "0.11.1", optional = true }
rust_decimal = { version = "1.37.2", default-features = false, optional = true }
spin-executor = { version = "5.0.0", path = "crates/executor" }
spin-macro = { version = "5.0.0", path = "crates/macro" }
thiserror = "1.0.37"
spin-wasip3-http = { version = "5.0.0", path = "crates/spin-wasip3-http", optional = true }
spin-wasip3-http-macro = { version = "5.0.0", path = "crates/spin-wasip3-http-macro", optional = true }
thiserror = { workspace = true }
uuid = { version = "1.18.0", optional = true }
wit-bindgen = { workspace = true }
routefinder = "0.5.3"
once_cell = { workspace = true }
futures = { workspace = true }
bytes = "1"
hyperium = { package = "http", version = "1.0.0" }
bytes = { workspace = true }
hyperium = { workspace = true }
serde_json = { version = "1.0.96", optional = true }
serde = { version = "1.0.163", optional = true }
wasi = { workspace = true }
Expand All @@ -42,6 +44,7 @@ default = ["export-sdk-language", "json", "postgres4-types"]
export-sdk-language = []
json = ["dep:serde", "dep:serde_json"]
postgres4-types = ["dep:rust_decimal", "dep:uuid", "dep:postgres_range", "json"]
wasip3-unstable = ["dep:spin-wasip3-http", "dep:spin-wasip3-http-macro"]

[workspace]
resolver = "2"
Expand All @@ -65,6 +68,9 @@ members = [
"examples/variables",
"examples/wasi-http-streaming-outgoing-body",
"examples/wasi-http-streaming-file",
"examples/wasip3-http-axum-router",
"examples/wasip3-http-hello-world",
"examples/wasip3-http-send-request",
"test-cases/simple-http",
"test-cases/simple-redis",
"crates/*",
Expand Down Expand Up @@ -92,12 +98,18 @@ authors = ["Spin Framework Maintainers <[email protected]>"]
edition = "2021"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/spinframework/spin-rust-sdk"
rust-version = "1.78"
rust-version = "1.86"
homepage = "https://spinframework.dev/rust-components"

[workspace.dependencies]
anyhow = "1"
hyperium = { package = "http", version = "1.3.1" }
http-body = "1.0.1"
http-body-util = "0.1.3"
bytes = "1.10.1"
wit-bindgen = "0.43.0"
futures = "0.3.28"
once_cell = "1.18.0"
thiserror = "2.0.17"
# Pin to the last version that targeted WASI 0.2.0
wasi = "=0.13.1"
21 changes: 21 additions & 0 deletions crates/spin-wasip3-http-macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "spin-wasip3-http-macro"
version.workspace = true
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
homepage.workspace = true
description = """
Rust procedural macros for Spin and WASIp3
"""

[lib]
name = "spin_wasip3_http_macro"
proc-macro = true

[dependencies]
proc-macro2 = "1"
quote = "1.0"
syn = { version = "1.0", features = [ "full" ]}
74 changes: 74 additions & 0 deletions crates/spin-wasip3-http-macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use proc_macro::TokenStream;
use quote::quote;

/// Marks an `async fn` as an HTTP component entrypoint for Spin.
///
/// The `#[http_service]` attribute designates an asynchronous function as the
/// handler for incoming HTTP requests in a Spin component using the WASI Preview 3
/// (`wasip3`) HTTP ABI.
///
/// When applied, this macro generates the necessary boilerplate to export the
/// function to the Spin runtime as a valid HTTP handler. The function must be
/// declared `async` and take a single argument implementing
/// [`FromRequest`](::spin_sdk::http_wasip3::FromRequest), typically
/// [`Request`](::spin_sdk::http_wasip3::Request), and must return a type that
/// implements [`IntoResponse`](::spin_sdk::http_wasip3::IntoResponse).
///
/// # Requirements
///
/// - The annotated function **must** be `async`.
/// - The function’s parameter type must implement [`FromRequest`].
/// - The return type must implement [`IntoResponse`].
///
/// If the function is not asynchronous, the macro emits a compile-time error.
///
/// # Example
///
/// ```ignore
/// use spin_sdk::http_wasip3::{http_service, Request, IntoResponse};
///
/// #[http_service]
/// async fn my_handler(request: Request) -> impl IntoResponse {
/// // Your logic goes here
/// }
/// ```
///
/// # Generated Code
///
/// The macro expands into a module containing a `Spin` struct that implements the
/// WASI `http.handler/Guest` interface, wiring the annotated function as the
/// handler’s entrypoint. This allows the function to be invoked automatically
/// by the Spin runtime when HTTP requests are received.
#[proc_macro_attribute]
pub fn http_service(_attr: TokenStream, item: TokenStream) -> TokenStream {
let func = syn::parse_macro_input!(item as syn::ItemFn);

if func.sig.asyncness.is_none() {
return syn::Error::new_spanned(
func.sig.fn_token,
"the `#[http_component]` function must be `async`",
)
.to_compile_error()
.into();
}

let func_name = &func.sig.ident;

quote!(
#func
mod __spin_wasip3_http {
use ::spin_sdk::http_wasip3::IntoResponse;

struct Spin;
::spin_sdk::http_wasip3::wasip3::http::proxy::export!(Spin);

impl ::spin_sdk::http_wasip3::wasip3::exports::http::handler::Guest for self::Spin {
async fn handle(request: ::spin_sdk::http_wasip3::wasip3::http::types::Request) -> Result<::spin_sdk::http_wasip3::wasip3::http::types::Response, ::spin_sdk::http_wasip3::wasip3::http::types::ErrorCode> {
let request = <::spin_sdk::http_wasip3::Request as ::spin_sdk::http_wasip3::FromRequest>::from_request(request)?;
::spin_sdk::http_wasip3::IntoResponse::into_response(super::#func_name(request).await)
}
}
}
)
.into()
}
17 changes: 17 additions & 0 deletions crates/spin-wasip3-http/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "spin-wasip3-http"
version.workspace = true
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
homepage.workspace = true

[dependencies]
anyhow = { workspace = true }
bytes = { workspace = true }
http-body = { workspace = true }
http-body-util = { workspace = true }
hyperium = { workspace = true }
wasip3 = { version = "0.2.1", features = ["http-compat"] }
Loading