gRPC services require dedicated client libraries, which makes them difficult to call from REST-based clients, browser apps, or third-party systems that only support HTTP/JSON. The ASMGrpcJsonTranscoder Custom Resource Definition (CRD) configures ingress gateways in Service Mesh (ASM) to accept HTTP/JSON requests and transcode them into gRPC calls at the gateway layer. No application code changes are needed -- REST clients access gRPC services through standard HTTP endpoints.
This guide walks through the end-to-end setup: annotating a .proto file with HTTP mappings, generating a proto descriptor, creating the ASMGrpcJsonTranscoder resource, and verifying the result.
How it works
The ingress gateway handles all transcoding. No application-level changes are required beyond the .proto annotation.
| Phase | What happens |
|---|---|
| 1. Configuration | The ASM control plane pushes three resources to the ingress gateway: an Envoy filter for gRPC transcoding, an Istio gateway, and a virtual service that routes traffic to the gRPC service port. The gateway loads these configurations immediately. |
| 2. Request path | The gateway receives an HTTP/JSON request, matches routing rules, transcodes the request to gRPC, and forwards it to the target gRPC service. |
| 3. Response path | The gateway receives the gRPC response from the backend service, transcodes it back to HTTP/JSON, and returns it to the client. |
Prerequisites
Before you begin, make sure that you have:
An ASM instance of Enterprise Edition or Ultimate Edition. See Create an ASM instance
A cluster added to the ASM instance
A gRPC sample service deployed in the cluster. See Use an ingress gateway to access a gRPC service in an ASM instance
Protocol Buffers (
protoc) installed locally
Add HTTP annotations and generate a proto descriptor
To map an HTTP endpoint to a gRPC method, add a google.api.http annotation in the .proto file and compile it into a .proto-descriptor file that the Envoy filter reads at runtime.
Annotate the .proto file
Add a google.api.http option to each RPC method that should accept HTTP/JSON requests. The following annotation maps GET /sayHello/{name} to the SayHello RPC:
option(google.api.http) = {
get: "/sayHello/{name}"
};The {name} path variable binds to the name field in HelloRequest. The annotation requires importing google/api/annotations.proto.
This example uses the helloworld service from grpc.io. Save the following content as helloworld.proto:
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
import "google/api/annotations.proto";
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {
option(google.api.http) = {
get: "/sayHello/{name}"
};
}
rpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {}
rpc SayHelloBidiStream (stream HelloRequest) returns (stream HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings.
message HelloReply {
string message = 1;
}Generate the .proto-descriptor file
Clone the googleapis repository, which provides the
google.api.httpannotation definition:git clone https://github.com/googleapis/googleapis.gitRun
protocto generate the descriptor:# Set the path to the directory containing helloworld.proto proto_path=<path/to/helloworld-grpc>/grpc/proto # Set the path to the cloned googleapis directory GOOGLEAPIS_DIR=<path/to/googleapis> protoc \ --proto_path=${proto_path} \ --proto_path=${GOOGLEAPIS_DIR} \ --include_imports \ --include_source_info \ --descriptor_set_out=helloworld.proto-descriptor \ "${proto_path}"/helloworld.protoReplace the following placeholders with actual values:
Placeholder Description Example <path/to/helloworld-grpc>Root directory of the helloworld gRPC project /home/user/helloworld-grpc<path/to/googleapis>Directory where you cloned googleapis /home/user/googleapisAfter the command succeeds, a
helloworld.proto-descriptorfile is created in the current directory.
Create the ASMGrpcJsonTranscoder resource
The ASMGrpcJsonTranscoder CRD instructs the ASM control plane to configure gRPC-JSON transcoding on the ingress gateway.
Save the following YAML as
grpcjsontranscoder-helloworld.yaml:apiVersion: istio.alibabacloud.com/v1beta1 kind: ASMGrpcJsonTranscoder metadata: name: grpcjsontranscoder-helloworld namespace: istio-system spec: isGateway: true # Apply the transcoder to the ingress gateway portNumber: 8080 # Port for HTTP/JSON requests workloadSelector: labels: istio: ingressgateway # Target the default ingress gateway printOptions: addWhitespace: true # Pretty-print JSON responses alwaysPrintEnumsAsInts: false # Print enum names instead of integer values alwaysPrintPrimitiveFields: false # Omit fields with default values from responses preserveProtoFieldNames: false # Use camelCase field names (protobuf default) priority: 0 services: - helloworld.Greeter # Fully qualified gRPC service name (<package>.<service>)Review the key fields:
Field Description Default isGatewaySet to trueto apply the transcoder on the ingress gateway rather than on sidecar proxies.falseportNumberThe port on the ingress gateway that accepts HTTP/JSON requests. -- workloadSelector.labelsLabel selector that identifies which gateway workload receives the Envoy filter. -- servicesList of fully qualified gRPC service names ( <package>.<service>) to transcode.-- printOptions.addWhitespacePretty-print JSON responses with indentation. falseprintOptions.alwaysPrintEnumsAsIntsPrint enum values as integers instead of names. falseprintOptions.alwaysPrintPrimitiveFieldsInclude fields with default values (e.g., an int32set to0) in the JSON response. Whenfalse, these fields are omitted.falseprintOptions.preserveProtoFieldNamesUse the original proto field names in JSON output instead of converting to camelCase. falseFor the full field reference, see ASMGrpcJsonTranscoder field descriptions.
Apply the resource:
kubectl apply -f grpcjsontranscoder-helloworld.yaml
Verify transcoding
After you apply the ASMGrpcJsonTranscoder resource, the ingress gateway accepts HTTP/JSON requests and transcodes them to gRPC.
Get the ingress gateway IP address:
kubectl -n istio-system get svc istio-ingressgateway \ -o jsonpath='{.status.loadBalancer.ingress[0].ip}'Send a test request to port 8080:
curl http://<ingress-gateway-ip>:8080/sayHello/MarkReplace
<ingress-gateway-ip>with the IP address from step 1.Verify the response. A successful response looks like this:
{ "message": "Hello, Mark! I'm from grpc-helloworld-py-v1-79b5dc9654-cg4dq!" }A JSON response from the backend gRPC service confirms that HTTP-to-gRPC transcoding is working.
What's next
ASMGrpcJsonTranscoder field descriptions: full CRD field reference.
Use an ingress gateway to access a gRPC service in an ASM instance: set up direct gRPC access without HTTP transcoding.