For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
gRPC-JSON transcoding
Configure HTTP-to-gRPC transcoding so that REST clients can communicate with gRPC backends through the gateway.
About gRPC-JSON transcoding
With gRPC-JSON transcoding, the gateway accepts incoming HTTP/JSON requests and transparently converts them into gRPC calls for your backend services. The gRPC response is also transcoded back to JSON and returned to the HTTP client. This way, REST clients, such as browsers and legacy systems, can talk to gRPC services without any protocol-specific code.
sequenceDiagram
participant Client as REST client
participant Gateway
participant Backend as gRPC service
Client->>Gateway: HTTP POST /yages.Echo/Ping
Gateway->>Backend: gRPC yages.Echo/Ping
Backend-->>Gateway: gRPC response
Gateway-->>Client: HTTP 200 {"text":"pong"}
You can map HTTP paths to gRPC methods in the following ways.
- Auto-mapping: Enable
autoMappingto automatically routePOST /package.Service/Methodrequests to the corresponding gRPC method. No changes to the.protofile are required. This is the simpler option and works well for third-party protos that you do not control. - HTTP annotations: Add
google.api.httpannotations to your.protofile to define explicit REST-to-gRPC mappings. For example, mapGET /v1/shelvesto theListShelvesgRPC method. Use this when you need custom URL paths, HTTP methods other than POST, or field-level mappings to path segments or query parameters.
gRPC-JSON transcoding is configured by setting the entGrpcJsonTranscoder field in an EnterpriseKgatewayTrafficPolicy resource and attaching it to an HTTPRoute. The policy activates Envoy’s native grpc_json_transcoder filter only for the targeted routes, so other routes on the same gateway are unaffected.
Note
Your gRPC backend must be configured for HTTP/2. Set appProtocol: http2 on the Service port to enable HTTP/2 connections to the backend. Without HTTP/2, transcoding fails at runtime. For more information, see HTTP/2.
Before you begin
Follow the Get started guide to install Solo Enterprise for kgateway.
Follow the Sample app guide to create a gateway proxy with an HTTP listener and deploy the httpbin sample app.
Get the external address of the gateway and save it in an environment variable.
export INGRESS_GW_ADDRESS=$(kubectl get svc -n kgateway-system http -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}") echo $INGRESS_GW_ADDRESSkubectl port-forward deployment/http -n kgateway-system 8080:8080
- Install
grpcurlto test gRPC services directly. - Install
curlto test transcoded HTTP requests. - Optional: Install
protocif you want to compile a proto descriptor from your own.protofiles.
Deploy a sample app
Deploy the yages gRPC echo service. The guide demonstrates HTTP/JSON to gRPC transcoding by using the yages.Echo.Ping method, which takes no input and returns {"text":"pong"}. The service also exposes yages.Echo.Reverse, which you can test directly with grpcurl.
Deploy the gRPC echo server.
kubectl apply -f - <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: grpc-echo namespace: kgateway-system labels: app: grpc-echo spec: selector: matchLabels: app: grpc-echo replicas: 1 template: metadata: labels: app: grpc-echo spec: containers: - name: grpc-echo image: ghcr.io/projectcontour/yages:v0.1.0 ports: - containerPort: 9000 protocol: TCP env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: GRPC_ECHO_SERVER value: "true" - name: SERVICE_NAME value: grpc-echo --- apiVersion: v1 kind: Service metadata: name: grpc-echo-svc namespace: kgateway-system labels: app: grpc-echo spec: type: ClusterIP ports: - port: 3000 protocol: TCP targetPort: 9000 appProtocol: http2 selector: app: grpc-echo EOFThe
appProtocol: http2tells the gateway to use HTTP/2 for connections to this service, which is required for gRPC-JSON transcoding.Verify that the pod is running.
kubectl get pods -n kgateway-system -l app=grpc-echoExample output:
NAME READY STATUS RESTARTS AGE grpc-echo-5fc549b5fc-tdlzw 1/1 Running 0 30s
Configure gRPC-JSON transcoding
Create an HTTPRoute that forwards traffic along the
grpc.example.comdomain to the gRPC echo service.kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: grpc-transcoding-route namespace: kgateway-system labels: app: grpc-echo spec: parentRefs: - name: http namespace: kgateway-system hostnames: - "grpc.example.com" rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: grpc-echo-svc port: 3000 EOFPrepare the proto descriptor. The gRPC-JSON transcoder requires a compiled proto descriptor to know how to map HTTP requests to gRPC calls. You provide this mapping as base64-encoded bytes in the EnterpriseKgatewayTrafficPolicy in the next step.
For the yages echo service, you can use the pre-compiled descriptor directly. Save it to an environment variable:
PROTO_DESCRIPTOR="CqEBCgt5YWdlcy5wcm90bxIFeWFnZXMiBwoFRW1wdHkiHQoHQ29udGVudBISCgR0ZXh0GAEgASgJUgR0ZXh0MlsKBEVjaG8SJgoEUGluZxIMLnlhZ2VzLkVtcHR5Gg4ueWFnZXMuQ29udGVudCIAEisKB1JldmVyc2USDi55YWdlcy5Db250ZW50Gg4ueWFnZXMuQ29udGVudCIAYgZwcm90bzM="If you have a
.protofile for your service, compile it into a descriptor withprotoc. Use--include_importsto make the descriptor self-contained.protoc \ --include_imports \ --descriptor_set_out=service.pb \ path/to/your/service.proto PROTO_DESCRIPTOR=$(base64 -i service.pb)For large descriptors or when you want to update the descriptor without changing the EnterpriseKgatewayTrafficPolicy, store it in a ConfigMap. See Use a ConfigMap for the proto descriptor for instructions, then reference it in the EnterpriseKgatewayTrafficPolicy resource by using the
protoDescriptorConfigMapfield.Create an EnterpriseKgatewayTrafficPolicy resource to configure the transcoder with your HTTP/JSON to gRPC mapping.
Review the following table to understand this configuration.kubectl apply -f - <<EOF apiVersion: enterprisekgateway.solo.io/v1alpha1 kind: EnterpriseKgatewayTrafficPolicy metadata: name: grpc-transcoding-policy namespace: kgateway-system labels: app: grpc-echo spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: grpc-transcoding-route entGrpcJsonTranscoder: protoDescriptorBin: ${PROTO_DESCRIPTOR} services: - yages.Echo autoMapping: true convertGrpcStatus: true EOFSetting Description entGrpcJsonTranscoder.protoDescriptorBinThe compiled proto descriptor as a base64-encoded string. entGrpcJsonTranscoder.servicesThe fully-qualified gRPC service names to transcode (for example, yages.Echoormain.Bookstore). Every name must exist in the descriptor.entGrpcJsonTranscoder.autoMappingWhen true, automatically routesPOST /package.Service/Methodrequests to the corresponding gRPC method without requiringgoogle.api.httpannotations in the proto.entGrpcJsonTranscoder.convertGrpcStatusWhen true, converts gRPC status trailers into HTTP status codes and JSON error bodies, so REST clients receive standard HTTP error semantics.
Verify transcoding
Verify that the gateway proxy transcodes HTTP requests to gRPC.
Send an HTTP POST request to the
Pingmethod. WithautoMappingenabled, the gateway maps the pathPOST /yages.Echo/Pingto the gRPCPingmethod.curl -X POST \ -H "Host: grpc.example.com" \ -H "Content-Type: application/json" \ -d '{}' \ http://$INGRESS_GW_ADDRESS:8080/yages.Echo/Pingcurl -X POST \ -H "Host: grpc.example.com" \ -H "Content-Type: application/json" \ -d '{}' \ http://localhost:8080/yages.Echo/PingExample output:
{"text":"pong"}Optional: Confirm that native gRPC clients can still reach the service directly.
grpcurl -plaintext \ -authority grpc.example.com \ $INGRESS_GW_ADDRESS:8080 \ yages.Echo/Pinggrpcurl -plaintext \ -authority grpc.example.com \ localhost:8080 \ yages.Echo/PingExample output:
{"text":"pong"}
Other configurations
Review other common configurations.
Use a ConfigMap for the proto descriptor
For large or frequently-updated descriptors, store the descriptor in a Kubernetes ConfigMap so you can update it independently of the policy. The control plane watches the ConfigMap and automatically rebuilds the gateway configuration when the descriptor changes.
Create a ConfigMap with the proto descriptor. Store the binary bytes in
binaryData(used verbatim) or the base64-encoded string indata.kubectl create configmap yages-proto-descriptor \ -n kgateway-system \ --from-file=descriptor.pb=service.pbkubectl apply -f - <<EOF apiVersion: v1 kind: ConfigMap metadata: name: yages-proto-descriptor namespace: kgateway-system labels: app: grpc-echo data: descriptor: ${PROTO_DESCRIPTOR} EOFUpdate the
EnterpriseKgatewayTrafficPolicyto reference the ConfigMap instead of the inline descriptor.kubectl apply -f - <<EOF apiVersion: enterprisekgateway.solo.io/v1alpha1 kind: EnterpriseKgatewayTrafficPolicy metadata: name: grpc-transcoding-policy namespace: kgateway-system labels: app: grpc-echo spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: grpc-transcoding-route entGrpcJsonTranscoder: protoDescriptorConfigMap: name: yages-proto-descriptor key: descriptor services: - yages.Echo autoMapping: true convertGrpcStatus: true EOFIf the ConfigMap is in a different namespace, set the
protoDescriptorConfigMap.namespacefield. Cross-namespace references require a ReferenceGrant.
Disable transcoding for specific routes
If you apply a transcoding policy at the Gateway level and want to opt a specific HTTPRoute out of transcoding, use disable: {} in a policy that targets that route.
kubectl apply -f - <<EOF
apiVersion: enterprisekgateway.solo.io/v1alpha1
kind: EnterpriseKgatewayTrafficPolicy
metadata:
name: no-transcoding
namespace: kgateway-system
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: my-plain-route
entGrpcJsonTranscoder:
disable: {}
EOFCleanup
You can optionally remove the resources that you set up as part of this guide.kubectl delete -A httproutes,EnterpriseKgatewayTrafficPolicy,deployments,services,configmaps -l app=grpc-echo