{"id":13740394,"url":"https://github.com/mercari/grpc-http-proxy","last_synced_at":"2025-04-05T17:07:55.276Z","repository":{"id":51269772,"uuid":"148621231","full_name":"mercari/grpc-http-proxy","owner":"mercari","description":"A reverse proxy server which translate JSON HTTP requests to gRPC calls based on protoreflect","archived":false,"fork":false,"pushed_at":"2023-07-05T20:32:50.000Z","size":359,"stargazers_count":374,"open_issues_count":8,"forks_count":15,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-03-29T16:08:06.514Z","etag":null,"topics":["grpc","http-proxy","kubernetes"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mercari.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-09-13T10:21:08.000Z","updated_at":"2025-01-22T15:17:57.000Z","dependencies_parsed_at":"2024-01-07T18:07:05.813Z","dependency_job_id":null,"html_url":"https://github.com/mercari/grpc-http-proxy","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mercari%2Fgrpc-http-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mercari%2Fgrpc-http-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mercari%2Fgrpc-http-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mercari%2Fgrpc-http-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mercari","download_url":"https://codeload.github.com/mercari/grpc-http-proxy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247369952,"owners_count":20927928,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["grpc","http-proxy","kubernetes"],"created_at":"2024-08-03T04:00:47.257Z","updated_at":"2025-04-05T17:07:55.261Z","avatar_url":"https://github.com/mercari.png","language":"Go","funding_links":[],"categories":["Tools"],"sub_categories":["Other"],"readme":"# grpc-http-proxy\n\n[![CircleCI](https://circleci.com/gh/mercari/grpc-http-proxy.svg?style=svg)](https://circleci.com/gh/mercari/grpc-http-proxy)\n\n**:warning: This is not production ready**\n\ngrpc-http-proxy is a reverse proxy which converts JSON HTTP requests to gRPC calls without much configuration.\nIt is designed to run in a Kubernetes cluster, and uses the Kubernetes API to find in-cluster servers that provide the desired gRPC service using custom Kubernetes annotations.\n\n![image](https://user-images.githubusercontent.com/1614811/45482670-a6b3bd80-b789-11e8-9243-70dac1a7fd41.png)\n\n## Background\nAlthough existing solutions, such as [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway),  generate reverse proxies that convert JSON HTTP requests to gRPC calls exist, they require the following to work:\n- Custom annotations to the gRPC service definitions must be manually be added to define the HTTP endpoint to gRPC method mappings.\n- The reverse proxy must be generated for each gRPC service.\n\nAs gRPC service definitions get larger, and more services are created, this can get unmanageable quickly.\n\ngrpc-http-proxy was created to be a single reverse proxy that works with all gRPC services, and without all the manual mapping. This enables gRPC services to be accessed through HTTP requests with less hassle than before.\n\n## How it works\n![image](https://user-images.githubusercontent.com/1614811/45482621-8e43a300-b789-11e8-96c9-dcba18f30aed.png)\n\nA request to the grpc-http-proxy's endpoint `/v1/\u003cservice\u003e/\u003cmethod\u003e` will make the proxy call the `\u003cmethod\u003e` method of the `\u003cservice\u003e` gRPC service.\n\nGiven the service name and method name are known, the gRPC call is made in the following steps:\n1. The [gRPC server reflection protocol](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) is used to obtain information from the gRPC service on the supported methods and the format of messages. \n2. The JSON request body is converted, using the information obtained above, to the Protobuf message by following the [Proto3 to JSON mapping specification](https://developers.google.com/protocol-buffers/docs/proto3#json).\n3. The gRPC call is made to the upstream service.\n4. The response is converted to JSON, and returned to the caller\n\nMetadata is passed to the upstream if it is put in the HTTP request's header, with the key prefixed with `Grpc-Metadata-`.\n\nAlso, grpc-http-proxy itself can be configured with an access token. If so, only requests with the specified access token in the `X-Access-Token` header are handled.\n\nMappings between gRPC service names and the upstream Kubernetes Services are defined by a custom annotation in the Kubernetes Service resource.\nThe Kubernetes API will be listened upon and the mapping will be kept up to date as Services with annotations are created, deleted, or updated.\n\n## Installation\nUse Helm to deploy to a Kubernetes cluster.\n\n```console\n$ git clone https://github.com/mercari/grpc-http-proxy \u0026\u0026 cd ./grpc-http-proxy\n$ helm install --name grpc-http-proxy helm/grpc-http-proxy --namespace kube-system\n```\n\nThis will deploy grpc-http-proxy without an access token to the `kube-system` namespace . To specify one, set the `accessToken` value as follows:\n\n```console\n$ helm install --set accessToken SUPER_SECRET --name grpc-http-proxy helm/grpc-http-proxy --namespace kube-system\n```\n\nAlso, there is a `values.yaml` file for more in-depth configuration.\n\n*note: RBAC is currently not supported by the Helm chart, so the default pod ServiceAccount should have access to all services within the cluster.*\n\n## Configuration\nAfter installing grpc-http-proxy, some configuration is required to make it find your services.\n\n### Enable gRPC reflection\nEnable server reflection in your gRPC servers by following the instructions found [here](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md#known-implementations).\n\n### Cluster side settings for Kubernetes API service discovery\nThe service discovery works by looking for Kubernetes Services with a specific annotation. In order to have it pick up the Kubernetes Service in front of your gRPC server, do the following.\n#### 1. Add the `grpc-service` annotation\nPut the `grpc-http-proxy.alpha.mercari.com/grpc-service` annotation on the Service. If your gRPC service's fully qualified name is `my.package.MyService`, add the annotation `grpc-http-proxy.alpha.mercari.com/grpc-service: my.package.MyService`.\n\n```diff\n  kind: Service\n  apiVersion: v1\n  metadata:\n    name: my-service\n    annotations:\n+     grpc-http-proxy.alpha.mercari.com/grpc-service: my.package.MyService\n```\n\nIf your gRPC server exports multiple services, specify them in a list delimited by a comma (`,`).\n\n```diff\n  kind: Service\n  apiVersion: v1\n  metadata:\n    name: my-service\n    annotation:\n+     grpc-http-proxy.alpha.mercari.com/grpc-service: my.package.MyService,my.anotherpackage.OtherService\n```\n\n#### 2. Name your port with a name which begins with `grpc`.\ngrpc-http-proxy will send requests to the port whose name begins with `grpc`. If there are multiple matching ports, the first one will be selected.\nThis step may be skipped if the port you intend to use is the only port exposed on the Kubernetes Service.\n\n```diff\n  kind: Service\n  apiVersion: v1\n  metadata:\n    name: my-service\n    annotations:\n      grpc-http-proxy.alpha.mercari.com/grpc-service: my.package.MyService\n  spec:\n    ports:\n-   - name: foo\n+   - name: grpc-foo\n      port: 5000\n      protocol: TCP\n      targetPort: 5000\n```\n\n#### 3. [optional] Add the `grpc-service-version` annotation\nIf you intend to call multiple versions of your gRPC server through grpc-http-proxy, put the `grpc-http-proxy.alpha.mercari.com/grpc-service-version` annotation on the Service.\nThe version can be any string you like.\n\n```diff\n    annotations:\n+    grpc-http-proxy.alpha.mercari.com/grpc-service-version: pr-42\n```\n\n## Examples\nIn the following examples, grpc-http-proxy is running at `grpc-http-proxy.example.com`, and have the access token set to `foo`.\nThe gRPC service `Echo` is called, which is defined by the following `.proto` file:\n\n```proto\nsyntax = \"proto3\";\n\npackage com.example;\n\nservice Echo {\n    rpc Say(EchoMessage) returns (EchoMessage) {};\n}\n\nmessage EchoMessage {\n    string message_body = 1;\n}\n```\n\n### Single version service\nThe Kubernetes Service manifest will look like this:\n\n```yaml\nkind: Service\napiVersion: v1\nmetadata:\n  name: echo-service\n  annotations:\n    grpc-http-proxy.alpha.mercari.com/grpc-service: com.example.Echo\nspec:\n  ports:\n  - name: grpc-echo\n    port: 5000\n    protocol: TCP\n    targetPort: 5000\n```\n\nThe request to call `Say` through grpc-http-proxy, and its response would be:\n\n```console\n$ curl -H'X-Access-Token: foo' -XPOST -d'{\"message_body\":\"Hello, World!\"}' grpc-http-proxy.example.com/v1/com.example.Echo/Say\n{\"message_body\":\"Hello, World!\"}\n```\n\n## Passing metadata to the gRPC service\nTo pass metadata with the key `somekey` to `Echo` service, add the metadata to the HTTP request like below:\n\n```console\n$ curl -H'X-Access-Token: foo' -H'Grpc-Metadata-somekey: value' -XPOST -d'{\"message_body\":\"Hello, World!\"}' grpc-http-proxy.example.com/v1/com.example.Echo/Say\n{\"message_body\":\"Hello, World!\"}\n```\n\n### Multiple versions of a service\nLet's say that you have a newer version of the `Echo` server in the same cluster that you would like to call . The Service manifest for the newer server should specify the version with an annotation, and would look like this:\n\n```yaml\nkind: Service\napiVersion: v1\nmetadata:\n  name: newer-echo-service\n  annotations:\n    grpc-http-proxy.alpha.mercari.com/grpc-service: com.example.Echo\n    grpc-http-proxy.alpha.mercari.com/grpc-service-version: newer-version\nspec:\n  ports:\n  - name: grpc-echo\n    port: 5000\n    protocol: TCP\n    targetPort: 5000\n```\n\nIn order to choose the new version, the version name specified in the annotation should be added as a query parameter.\nThe request to call `Say` on the newer server, and its response would be:\n\n```console\n$ curl -H'X-Access-Token: foo' -XPOST -d'{\"message_body\":\"Hello, World!\"}' grpc-http-proxy.example.com/v1/com.example.Echo/Say?version=newer-version\n{\"message_body\":\"Hello, World!\"}\n```\n\n## TODOs\nA non-exhaustive list of additional features that could be desired:\n- Ability to find services though a static configuration file.\n\nContributions are welcomed :)\n\n## Committers\nTomoya TABUCHI ([@tomoyat1](https://github.com/tomoyat1))\n\n## Contribution\nPlease read the CLA below carefully before submitting your contribution.\n\nhttps://www.mercari.com/cla/\n\n## LICENSE\nCopyright 2018 Mercari, Inc.\n\nLicensed under the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmercari%2Fgrpc-http-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmercari%2Fgrpc-http-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmercari%2Fgrpc-http-proxy/lists"}