Skip to main content

spin_sdk/http/
grpc.rs

1//! gRPC helpers for serving tonic services from Spin components.
2//!
3//! This module provides a thin integration layer between the Spin HTTP
4//! subsystem and [tonic](https://docs.rs/tonic)-generated gRPC servers.
5//! Tonic's generated server types (e.g. `GreeterServer<T>`) implement
6//! [`tower_service::Service`] over HTTP requests, so they can accept
7//! Spin's incoming [`Request`](crate::http::Request) directly.
8//!
9//! # Example
10//!
11//! ```ignore
12//! use spin_sdk::http::{IntoResponse, Request};
13//! use spin_sdk::http_service;
14//! #[http_service]
15//! async fn handler(req: Request) -> impl IntoResponse {
16//!     spin_sdk::grpc::serve(GreeterServer::new(MyGreeter), req).await
17//! }
18//! ```
19
20use hyperium as http;
21use std::convert::Infallible;
22
23/// Serve a gRPC request by forwarding it to a tower service.
24///
25/// This function is designed to work with tonic-generated server types,
26/// which implement `tower::Service<http::Request<B>>` for any body `B`
27/// satisfying `http_body::Body + Send + 'static`.
28///
29/// The response is returned as an [`http::Response<B>`] which implements
30/// [`IntoResponse`](crate::http::IntoResponse), so it integrates directly
31/// with the `#[http_service]` handler return type.
32///
33/// # Extracting a gRPC service from a [`Router`]
34///
35/// If you have multiple services, you can compose them with
36/// [`tonic::transport::server::Router`] at the type level, or simply
37/// match on the request path and delegate to different `serve` calls.
38///
39/// # Example
40///
41/// ```ignore
42/// use spin_sdk::http::{IntoResponse, Request};
43/// use spin_sdk::{grpc, http_service};
44/// #[http_service]
45/// async fn handler(req: Request) -> impl IntoResponse {
46///     grpc::serve(GreeterServer::new(MyGreeter), req).await
47/// }
48/// ```
49pub async fn serve<S, B>(mut svc: S, req: crate::http::Request) -> http::Response<B>
50where
51    S: tower_service::Service<
52        crate::http::Request,
53        Response = http::Response<B>,
54        Error = Infallible,
55    >,
56{
57    // Infallible error — unwrap is safe.
58    svc.call(req).await.unwrap_or_else(|e| match e {})
59}