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.
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.
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