Skip to content

Interceptors in gRPC Controllers

Sword lets you apply interceptors to gRPC controllers to validate or transform the incoming metadata of remote calls.

Traditional interceptors

The OnRequest Trait

In gRPC, OnRequest lets you intercept the request before it reaches the service method.

rust
use sword::grpc::*;
use sword::prelude::*;

#[derive(Interceptor)]
struct AuthInterceptor;

#[sword::grpc::async_trait]
impl OnRequest for AuthInterceptor {
    async fn on_request(&self, req: Request<()>) -> GrpcInterceptorResult {
        if req.metadata().get("authorization").is_none() {
            return Err(Status::unauthenticated("missing authorization metadata"));
        }

        Ok(req)
    }
}
rust
use sword::prelude::*;

#[controller(kind = Controller::Grpc, service = proto::user_service_server::UserServiceServer)]
#[interceptor(AuthInterceptor)]
struct UsersController;

No next()

Unlike web interceptors, there is no next() in this variant: the interceptor validates/transforms the incoming metadata and returns Ok(req) or an error Status.

Interceptors with configuration

The OnRequestWithConfig Trait

In gRPC you can use OnRequestWithConfig<T> to inject configuration parameters into the validation/interception.

rust
use sword::grpc::*;
use sword::prelude::*;

#[derive(Interceptor)]
struct ApiKeyInterceptor;

#[sword::grpc::async_trait]
impl OnRequestWithConfig<&'static str> for ApiKeyInterceptor {
    async fn on_request(
        &self,
        expected_key: &'static str,
        req: Request<()>,
    ) -> GrpcInterceptorResult {
        let Some(value) = req.metadata().get("x-api-key") else {
            return Err(Status::unauthenticated("missing x-api-key"));
        };

        let Ok(value) = value.to_str() else {
            return Err(Status::unauthenticated("invalid x-api-key"));
        };

        if value != expected_key {
            return Err(Status::permission_denied("invalid x-api-key"));
        }

        Ok(req)
    }
}
rust
use sword::prelude::*;

#[controller(kind = Controller::Grpc, service = proto::user_service_server::UserServiceServer)]
#[interceptor(ApiKeyInterceptor, config = "dev-key")]
struct UsersController;