gRPC Support

bext serves gRPC natively on the same HTTP port — no sidecar proxy or separate listener required. HTTP/2 requests with content-type: application/grpc are routed to the gRPC handler automatically.

Enabling gRPC

Add a [grpc] section to bext.config.toml and register your services:

[grpc]
enabled = true

[[grpc.services]]
name = "greeter"
proto = "proto/greeter.proto"
handler = "plugins/greeter-service"

[[grpc.services]]
name = "orders"
proto = "proto/orders.proto"
handler = "plugins/order-service"

Each service entry requires:

Field Description
name Logical name used in logs and metrics.
proto Path to the .proto file defining the service.
handler Plugin or module that implements the service methods.

bext parses the .proto at startup and generates the routing table. If a client calls a method not declared in the proto, it receives UNIMPLEMENTED immediately.

grpc-web Transcoding

Browser clients cannot use native gRPC (no HTTP/2 trailers in browser fetch). bext detects Content-Type: application/grpc-web or application/grpc-web+proto and automatically transcodes:

- Base64-encoded framing for grpc-web-text

- Binary framing for grpc-web+proto

- CORS headers injected from the site's [cors] config

No separate Envoy or grpc-web proxy is needed.

Plugin Compatibility

Plugins that handle gRPC requests declare protocol support in their manifest:

# plugin.toml
[plugin]
name = "greeter-service"
protocols = ["http", "grpc"]

A plugin that only declares protocols = ["http"] will never receive gRPC calls. This prevents accidental routing and makes protocol support explicit.

Inside a gRPC handler, the plugin receives a GrpcRequest with the decoded message and metadata:

fn greet(req: GrpcRequest<HelloRequest>) -> GrpcResult<HelloReply> {
    Ok(HelloReply {
        message: format!("Hello, {}!", req.message.name),
    })
}

Authentication

Auth works via gRPC metadata. Clients set the authorization metadata key with a bearer token, and bext's Auth middleware validates it exactly as it would an HTTP Authorization header:

authorization: Bearer eyJhbGciOi...

The same auth providers (JWT, API key, OAuth) apply to gRPC calls. Denied requests receive UNAUTHENTICATED or PERMISSION_DENIED status codes.

Cache Integration

Unary (request-response) gRPC calls can be cached. bext hashes the service name, method name, and serialized request message to produce a cache key. Enable per-method:

[[grpc.services]]
name = "catalog"
proto = "proto/catalog.proto"
handler = "plugins/catalog-service"

[grpc.services.cache]
methods = ["GetProduct", "ListCategories"]
ttl_secs = 60

Streaming calls are never cached.

Streaming

bext supports all four gRPC call types:

Type Description
Unary Single request, single response.
Server streaming Single request, stream of responses.
Client streaming Stream of requests, single response.
Bidi streaming Full duplex streams in both directions.

Streaming calls respect the site's max_concurrent_streams setting from the [http2] config. Idle streams are reaped after stream_idle_secs (default 300).

Reflection

When reflection = true is set in the [grpc] section, bext exposes the gRPC Server Reflection service so tools like grpcurl and Postman can introspect available services without a local .proto file:

[grpc]
enabled = true
reflection = true

Health Checking

bext implements the standard gRPC Health Checking Protocol (grpc.health.v1.Health). Each registered service is reported as SERVING once its handler is loaded. Use this for load balancer probes:

grpcurl -plaintext localhost:443 grpc.health.v1.Health/Check

Feature Flag

gRPC support requires the grpc feature flag at compile time:

bext build --features grpc

Without this flag, the [grpc] config section is ignored and no gRPC routing is compiled in.

Tip

Streaming calls (server, client, and bidi) are never cached — only unary (request/response) methods are eligible. Set methods explicitly in [grpc.services.cache] to avoid accidentally caching non-idempotent calls.

Tip

Browser clients cannot use native gRPC. If your consumers include web frontends, enable grpc-web transcoding (built-in) and verify that Content-Type: application/grpc-web+proto reaches bext unmodified — CDN or proxy rewrites of this header will break transcoding silently.

Related

- WebSockets — alternative for browser realtime when grpc-web is not suitable

- Auth capability — JWT and API key validation applied to gRPC metadata

- Plugins overview — how gRPC handler plugins are packaged and loaded

- Configuration reference — full bext.config.toml field listing

- Caching guide — TTL and cache-key mechanics used by unary method caching

Links

- grpc.io — official gRPC project site, protocol specification, and language guides