Akamai to acquire LayerX to enforce AI usage control on any browser. Get details

Introducing wasi-grpc for Spin

Brian Hardock profile

Sep 08, 2025

Brian Hardock

Brian Hardock profile

Written by

Brian Hardock

Brian is a Senior Software Engineer at Akamai. He is the lead on the Functions developer experiences team and a core maintainer of the CNCF Spinframework/Spin project.

Share

Modern microservice ecosystems often rely on gRPC for efficient, strongly typed communication. gRPC builds on top of HTTP/2, taking advantage of multiplexed streams and binary serialization (Protobuf) to deliver high throughput and low latency.

Until Spin 3.4, Spin components could only make outbound HTTP/1.1 requests. This meant gRPC clients could not run inside Spin directly; developers instead had to rely on sidecars or proxy services to bridge the gap. This added extra complexity and slowed down applications.

Spin 3.4 introduces outbound HTTP/2 support, enabling components to act as first-class gRPC clients. Spin applications can now call into existing gRPC-based systems, cloud APIs, and service meshes directly, without workarounds.

In this blog post, we will walk through a tutorial showing how to build a Spin component in Rust that connects to a simple gRPC service using the new wasi-grpc crate.

Tutorial

For this tutorial, we will be adapting the tonic helloworld example client to execute in Spin. Additionally, for testing, we will run the helloworld server to execute our component against.

Step 1: Create a new Spin app

spin new -t http-rust helloworld-client --accept-defaults

This creates a new helloworld-client directory with a Spin HTTP Rust application. Change into this directory to continue with the tutorial:

cd helloworld-client

Step 2: Setup

First, in Cargo.toml, add the dependencies for working with gRPC, Protobuf, and the wasi-grpc crate:

[dependencies]
anyhow = "1"
prost = "0.13.5"
wasi-grpc = "0.1.0"
spin-sdk = "4.0.0"
tonic = { version = "0.13.1", features = ["codegen", "prost", "router"], default-features = false}

Next, copy the helloworld proto into your current working directory.

With that in place, we can add our build dependencies for generating code from our proto file. In your Cargo.toml add the following:

[build-dependencies]
tonic-build = { version = "0.13.1", features = ["prost"] }

And finally we can add the build.rs which will generate our gRPC client from the helloworld proto:

// In build.rs
fn main() {
    tonic_build::configure()
        .build_transport(false)
        .compile_protos(&["helloworld.proto"], &[""])
        .unwrap();
}

Let's implement

In src/lib.rs, let's start by pulling in the generated code from executing our build.rs:

use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;
 
pub mod hello_world {
    tonic::include_proto!("helloworld");
}

Next let's pull in the wasi_grpc::WasiGrpcEndpoint type which implements tower_service::Service. This type creates a bridge between tonic and wasi-hyperium which is what wasi-grpc uses under the hood for sending outbound HTTP requests.

use wasi_grpc::WasiGrpcEndpoint;
NOTE: It was decided to use wasi-hyperium as the underlying mechanism for sending outbound requests because the spin-sdk currently has certain limitations with respect to outbound streaming.

And finally we can implement our request handler:

#[http_component]
async fn handler(_req: http::Request) -> anyhow::Result<impl IntoResponse> {
    let endpoint_uri = "http://[::1]:50051".parse().context("Failed to parse endpoint URI")?;
    let endpoint = WasiGrpcEndpoint::new(endpoint_uri);
    let mut client = GreeterClient::new(endpoint);
 
    let request = Request::new(HelloRequest {
        name: "World".to_string(),
    });
 
    let message = client
        .say_hello(request)
        .await?
        .into_inner()
        .message;
 
    let response = http::Response::new(200, message);
    Ok(response)
}
NOTE: For simplicity, we are using a hardcoded endpoint to communicate with our local gRPC server. For production applications it is recommended to use application variables to inject in the value of the address at run/deploy time.

Putting this all together, the final code in src/lib.rs looks like this:

use anyhow::Context;
use spin_sdk::http::{self, IntoResponse};
use spin_sdk::http_component;
use tonic::Request;
use wasi_grpc::WasiGrpcEndpoint;
 
use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;
 
pub mod hello_world {
    tonic::include_proto!("helloworld");
}
 
#[http_component]
async fn handler(_req: http::Request) -> anyhow::Result<impl IntoResponse> {
    let endpoint_uri = "http://[::1]:50051".parse().context("Failed to parse endpoint URI")?;
    let endpoint = WasiGrpcEndpoint::new(endpoint_uri);
    let mut client = GreeterClient::new(endpoint);
 
    let request = Request::new(HelloRequest {
        name: "World".to_string(),
    });
 
    let message = client
        .say_hello(request)
        .await?
        .into_inner()
        .message;
 
    let response = http::Response::new(200, message);
    Ok(response)
}

Let's take it for a Spin!

As mentioned earlier, we will be using the helloworld server to execute our app. The easiest way to run this would be to clone the tonic repository and run the helloworld server:

$ gh repo clone hyperium/tonic
$ cargo run --bin helloworld-server
...
GreeterServer listening on [::1]:50051

Next, we will want to configure our Spin app so that our component can communicate with the server running at [::1]:50051. In your spin.toml, you'll want to add the following:

[component.helloworld-client]
...
allowed_outbound_hosts = ["http://[::1]:50051"]

Now that we have our server running and app properly configured, let's spin up our application and send it a request:

$ SPIN_OUTBOUND_H2C_PRIOR_KNOWLEDGE=[::1]:50051 spin up --build
NOTE: The SPIN_OUTBOUND_H2C_PRIOR_KNOWLEDGE environment variable is to tell the Spin runtime that we are intending to use HTTP/2 without TLS.

And finally, let's send a request to our app:

$ curl localhost:3000/
Hello World!

Conclusion

Spin 3.4's outbound HTTP/2 support removes one of the biggest barriers to using Spin in modern service-oriented systems: direct gRPC client support. With the help of the wasi-grpc crate, components can now:

  • Call gRPC microservices directly without sidecars
  • Integrate with APIs built on gRPC
  • Leverage high-performance streaming patterns as first-class citizens in Spin

The example above uses the simple helloworld service, but the same approach applies to more advanced services, including streaming APIs. For inspiration, check out the routeguide-client in the wasi-grpc repository.

If you have any questions, we'd love to help in the Spin CNCF Slack channel. Hope to see you there.

Brian Hardock profile

Sep 08, 2025

Brian Hardock

Brian Hardock profile

Written by

Brian Hardock

Brian is a Senior Software Engineer at Akamai. He is the lead on the Functions developer experiences team and a core maintainer of the CNCF Spinframework/Spin project.

Tags

Share

Related Blog Posts

Developers
Akamai Blog | How to Get Started With Application Security
December 21, 2021
With a comprehensive security stack, Akamai’s application security solutions defend your entire ecosystem from threats. But before you can reap the benefits that come with application security, you need to create a configuration with Akamai’s APIs. Our Developer Advocacy team is here to walk you through the process so you can achieve Infrastructure as Code — or, as we like to call it here, Akamai as Code. Akamai as Code has the ability to support all the DevSecOps practices you know and love, such as automating repetitive tasks and streamlining configurations and workflows, along with reducing manual work and errors.
Cloud
What’s New for Developers: July 2024
July 19, 2024
July's updates include details on Akamai PowerShell Module 2.0, a post on high bounce rates on fast websites, and tips for video transcoding.
Cloud
Securing Video Contribution Feeds with Akamai’s Distributed Cloud & CDN
March 28, 2025
EZDRM is an independent software vendor (ISV) in the Akamai Qualified Compute Partner Program. EZDRM’s security resources for the Secure CDN Contribution solution are deployed on Akamai’s cloud infrastructure.