All Products
Search
Document Center

Alibaba Cloud Service Mesh:Transcode HTTP/JSON requests to gRPC with ASMGrpcJsonTranscoder

Last Updated:Mar 11, 2026

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.

PhaseWhat happens
1. ConfigurationThe 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 pathThe gateway receives an HTTP/JSON request, matches routing rules, transcodes the request to gRPC, and forwards it to the target gRPC service.
3. Response pathThe 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:

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

  1. Clone the googleapis repository, which provides the google.api.http annotation definition:

       git clone https://github.com/googleapis/googleapis.git
  2. Run protoc to 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.proto

    Replace the following placeholders with actual values:

    PlaceholderDescriptionExample
    <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/googleapis

    After the command succeeds, a helloworld.proto-descriptor file 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.

  1. 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>)
  2. Review the key fields:

    FieldDescriptionDefault
    isGatewaySet to true to apply the transcoder on the ingress gateway rather than on sidecar proxies.false
    portNumberThe 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.false
    printOptions.alwaysPrintEnumsAsIntsPrint enum values as integers instead of names.false
    printOptions.alwaysPrintPrimitiveFieldsInclude fields with default values (e.g., an int32 set to 0) in the JSON response. When false, these fields are omitted.false
    printOptions.preserveProtoFieldNamesUse the original proto field names in JSON output instead of converting to camelCase.false
  3. 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.

  1. Get the ingress gateway IP address:

       kubectl -n istio-system get svc istio-ingressgateway \
           -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
  2. Send a test request to port 8080:

       curl http://<ingress-gateway-ip>:8080/sayHello/Mark

    Replace <ingress-gateway-ip> with the IP address from step 1.

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