Skip to main content
Version: 3.0

grpc-transcode

Description#

The grpc-transcode Plugin converts between HTTP and gRPC requests.

APISIX takes in an HTTP request, transcodes it and forwards it to a gRPC service, gets the response and returns it back to the client in HTTP format.

Attributes#

NameTypeRequiredDefaultDescription
proto_idstring/integerTrueid of the the proto content.
servicestringTrueName of the gRPC service.
methodstringTrueMethod name of the gRPC service.
deadlinenumberFalse0Deadline for the gRPC service in ms.
pb_optionarray[string(pb_option_def)]Falseprotobuf options.

Options for pb_option#

TypeValid values
enum as resultenum_as_name, enum_as_value
int64 as resultint64_as_number, int64_as_string, int64_as_hexstring
default valuesauto_default_values, no_default_values, use_default_values, use_default_metatable
hooksenable_hooks, disable_hooks

Enabling the Plugin#

Before enabling the Plugin, you have to add the content of your .proto or .pb files to APISIX.

You can use the /admin/protos/id endpoint and add the contents of the file to the content field:

curl http://127.0.0.1:9180/apisix/admin/protos/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"content" : "syntax = \"proto3\";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}"
}'

If your proto file contains imports, or if you want to combine multiple proto files, you can generate a .pb file and use it in APISIX.

For example, if we have a file called proto/helloworld.proto which imports another proto file:

syntax = "proto3";

package helloworld;
import "proto/import.proto";
...

We first generate a .pb file from the proto files:

protoc --include_imports --descriptor_set_out=proto.pb proto/helloworld.proto

The output binary file, proto.pb will contain both helloworld.proto and import.proto.

We can now use the content of proto.pb in the content field of the API request.

As the content of the proto is binary, we encode it in base64 using this Python script:

upload_pb.py
#!/usr/bin/env python
# coding: utf-8

import base64
import sys

# sudo pip install requests
import requests

if len(sys.argv) <= 1:
print("bad argument")
sys.exit(1)
with open(sys.argv[1], 'rb') as f:
content = base64.b64encode(f.read())
id = sys.argv[2]
api_key = "edd1c9f034335f136f87ad84b625c8f1" # use a different API key

reqParam = {
"content": content,
}
resp = requests.put("http://127.0.0.1:9180/apisix/admin/protos/" + id, json=reqParam, headers={
"X-API-KEY": api_key,
})
print(resp.status_code)
print(resp.text)

This script will take in a .pb file and the id to create, encodes the content of the proto to base64, and calls the Admin API with this encoded content.

To run the script:

chmod +x ./upload_pb.py
./upload_pb.py proto.pb 1

Response:

# 200
# {"node":{"value":{"create_time":1643879753,"update_time":1643883085,"content":"CmgKEnByb3RvL2ltcG9ydC5wcm90bxIDcGtnIhoKBFVzZXISEgoEbmFtZRgBIAEoCVIEbmFtZSIeCghSZXNwb25zZRISCgRib2R5GAEgASgJUgRib2R5QglaBy4vcHJvdG9iBnByb3RvMwq9AQoPcHJvdG8vc3JjLnByb3RvEgpoZWxsb3dvcmxkGhJwcm90by9pbXBvcnQucHJvdG8iPAoHUmVxdWVzdBIdCgR1c2VyGAEgASgLMgkucGtnLlVzZXJSBHVzZXISEgoEYm9keRgCIAEoCVIEYm9keTI5CgpUZXN0SW1wb3J0EisKA1J1bhITLmhlbGxvd29ybGQuUmVxdWVzdBoNLnBrZy5SZXNwb25zZSIAQglaBy4vcHJvdG9iBnByb3RvMw=="},"key":"\/apisix\/proto\/1"}}

Now, we can enable the grpc-transcode Plugin to a specific Route:

curl http://127.0.0.1:9180/apisix/admin/routes/111 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"methods": ["GET"],
"uri": "/grpctest",
"plugins": {
"grpc-transcode": {
"proto_id": "1",
"service": "helloworld.Greeter",
"method": "SayHello"
}
},
"upstream": {
"scheme": "grpc",
"type": "roundrobin",
"nodes": {
"127.0.0.1:50051": 1
}
}
}'
note

The Upstream service used here should be a gRPC service. Note that the scheme is set to grpc.

You can use the grpc_server_example for testing.

Example usage#

Once you configured the Plugin as mentioned above, you can make a request to APISIX to get a response back from the gRPC service (through APISIX):

curl -i http://127.0.0.1:9080/grpctest?name=world

Response:

HTTP/1.1 200 OK
Date: Fri, 16 Aug 2019 11:55:36 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX web server
Proxy-Connection: keep-alive

{"message":"Hello world"}

You can also configure the pb_option as shown below:

curl http://127.0.0.1:9180/apisix/admin/routes/23 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"methods": ["GET"],
"uri": "/zeebe/WorkflowInstanceCreate",
"plugins": {
"grpc-transcode": {
"proto_id": "1",
"service": "gateway_protocol.Gateway",
"method": "CreateWorkflowInstance",
"pb_option":["int64_as_string"]
}
},
"upstream": {
"scheme": "grpc",
"type": "roundrobin",
"nodes": {
"127.0.0.1:26500": 1
}
}
}'

Now if you check the configured Route:

curl -i "http://127.0.0.1:9080/zeebe/WorkflowInstanceCreate?bpmnProcessId=order-process&version=1&variables=\{\"orderId\":\"7\",\"ordervalue\":99\}"
HTTP/1.1 200 OK
Date: Wed, 13 Nov 2019 03:38:27 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
grpc-encoding: identity
grpc-accept-encoding: gzip
Server: APISIX web server
Trailer: grpc-status
Trailer: grpc-message

{"workflowKey":"#2251799813685260","workflowInstanceKey":"#2251799813688013","bpmnProcessId":"order-process","version":1}

Disable Plugin#

To disable the grpc-transcode Plugin, you can delete the corresponding JSON configuration from the Plugin configuration. APISIX will automatically reload and you do not have to restart for this to take effect.

curl http://127.0.0.1:9180/apisix/admin/routes/111 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/grpctest",
"plugins": {},
"upstream": {
"scheme": "grpc",
"type": "roundrobin",
"nodes": {
"127.0.0.1:50051": 1
}
}
}'