{"id":16813747,"url":"https://github.com/albertoimpl/spring-cloud-gateway-grpc","last_synced_at":"2025-03-22T03:31:12.868Z","repository":{"id":38410815,"uuid":"429084494","full_name":"Albertoimpl/spring-cloud-gateway-grpc","owner":"Albertoimpl","description":"Blog post describing how to enable gRPC support in the latest Spring Cloud Gateway","archived":false,"fork":false,"pushed_at":"2022-06-23T12:20:52.000Z","size":160,"stargazers_count":32,"open_issues_count":0,"forks_count":13,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-18T07:32:12.913Z","etag":null,"topics":["grpc","java","spring","spring-cloud-gateway"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Albertoimpl.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-17T14:44:28.000Z","updated_at":"2024-12-27T03:49:18.000Z","dependencies_parsed_at":"2022-08-28T06:41:06.502Z","dependency_job_id":null,"html_url":"https://github.com/Albertoimpl/spring-cloud-gateway-grpc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Albertoimpl%2Fspring-cloud-gateway-grpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Albertoimpl%2Fspring-cloud-gateway-grpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Albertoimpl%2Fspring-cloud-gateway-grpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Albertoimpl%2Fspring-cloud-gateway-grpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Albertoimpl","download_url":"https://codeload.github.com/Albertoimpl/spring-cloud-gateway-grpc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244902929,"owners_count":20529114,"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","java","spring","spring-cloud-gateway"],"created_at":"2024-10-13T10:27:44.733Z","updated_at":"2025-03-22T03:31:12.293Z","avatar_url":"https://github.com/Albertoimpl.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Spring Cloud Gateway and gRPC\n\nStarting from `3.1.0` as part of the Spring Cloud 2021.0.0 (aka Jubilee) release train, Spring Cloud Gateway included support for gRPC and HTTP/2.\n\nWe will introduce the basic concepts behind gRPC and how to configure it with two examples:\n\n* One that showcases how Spring Cloud Gateway can transparently re-route gRPC traffic without needing to know the proto definition and without having to modify our existing gRPC servers.\n\n* Another that showcases how we can create a custom filter in Spring Cloud Gateway to transform a JSON payload to a gRPC message.\n\n\n== Introduction to gRPC and HTTP/2\n\nHTTP/2 makes our applications faster, simpler, and more robust. Reducing latency by enabling request and response\nmultiplexing, adding efficient compression of HTTP header fields, and adding support for request prioritization and\nserver push.\n\nThe reduction in the number of connections is particularly important when improving the performance of HTTPS: that way\nwe have less expensive TLS handshakes, more efficient session reuse, reducing client and server resources.\n\nHTTP/2 provides two mechanisms for negotiating the application level protocol:\n\n* `H2C` HTTP/2.0 support with clear-text\n* `H2` HTTP/2.0 support with TLS\n\nEven though `reactor-netty` has support for `H2C` clear-text protocol, Spring Cloud Gateway requires `H2` with TLS to\nassure transport security.\n\nHTTP/2 adds a binary framing layer, which is how the HTTP messages are encapsulated and transferred between the client\nand server, enabling more efficient ways to transfer data.\n\nThanks to https://github.com/reactor/reactor-netty[reactor-netty] and its HTTP/2 support, we were able to extend\nSpring Cloud Gateway to support gRPC.\n\nhttps://grpc.io/[gRPC] is a high-performance Remote Procedure Call framework that can run in any environment. It\nprovides bi-directional streaming, and it's based on HTTP/2.\n\ngRPC services can be defined using Protocol Buffers, a powerful binary serialization toolset and language, and\nprovides tools for generating clients and servers across different languages.\n\n== Getting started\n\nIn order to enable gRPC in Spring Cloud Gateway, we need to enable HTTP/2 and SSL in our project https://docs.oracle.com/cd/E19830-01/819-4712/ablqw/index.html[by adding a keystore], this can be done\nthrough configuration by adding the following:\n\n[source,yaml]\n----\nserver:\n  http2:\n    enabled: true\n  ssl:\n    key-store-type: PKCS12\n    key-store: classpath:keystore.p12\n    key-store-password: password\n    key-password: password\n    enabled: true\n\n----\n\nNow that we have it enabled, we can create a route that redirects traffic to a gRPC server and take advantage of the\nexisting filters and predicates, for example, this route will redirect traffic that comes from any path starting\nwith `grpc` to a local server in the port `6565` and add header `X-Request-header` with the value `header-value`:\n\n[source,yaml]\n----\nspring:\n  cloud:\n    gateway:\n      routes:\n        - id: grpc\n          uri: https://localhost:6565\n          predicates:\n            - Path=/grpc/**\n          filters:\n            - AddResponseHeader=X-Request-header, header-value\n----\n\n== Running gRPC to gRPC\n\nAn end to end example can be found in this repository with the following parts:\n\nimage::grpc-simple-gateway.png[grpc-simple-gateway]\n\n\n* A `grpc-server` that exposes a `HelloService`, and gRPC endpoint to receive a `HelloRequest` and return\n a `HelloResponse`:\n[source,protobuf]\n----\nsyntax = \"proto3\";\n\nmessage HelloRequest {\n  string firstName = 1;\n  string lastName = 2;\n}\n\nmessage HelloResponse {\n  string greeting = 1;\n}\n\nservice HelloService {\n  rpc hello(HelloRequest) returns (HelloResponse);\n}\n----\n\nThe server will concatenate a salutation with `firstName` and a `lastName` and respond with a `greeting`.\n\nFor example, this input:\n\n[source,text]\n----\nfirstName: Saul\nlastName: Hudson\n----\n\nWill output:\n\n[source,text]\n----\ngreeting: Hello, Saul Hudson\n----\n\n* A `grpc-client`, in charge of sending the `HelloRequest` to the `HelloService`.\n\n* `grpc-simple-gateway` that routes the requests and adds a header with the configuration mentioned above. Note that this gateway application does not have any dependency to gRPC nor to the proto definition used by client and server.\n\nAt the moment there is just one route that will forward everything to the `grpc-server`:\n\n[source,yaml]\n----\n      routes:\n        - id: grpc\n          uri: https://localhost:6565\n          predicates:\n            - Path=/**\n          filters:\n            - AddResponseHeader=X-Request-header, header-value\n----\n\nTo start the server that is going to be listening to requests:\n\n[source,shell]\n----\n ./gradlew :grpc-server:bootRun\n----\n\nThen, we start the gateway that is going to re-route the gRPC requests:\n\n[source,shell]\n----\n./gradlew :grpc-simple-gateway:bootRun\n----\n\nFinally, we can use the client that points to the gateway application:\n\n[source,shell]\n----\n./gradlew :grpc-client:bootRun\n----\n\nThe gateway routes and filters can be modified in https://github.com/Albertoimpl/spring-cloud-gateway-grpc/blob/5bf80a24a8adf0d5d7c1614524f9d55707536c19/grpc-simple-gateway/src/main/resources/application.yaml#L14[grpc-simple-gateway/src/main/resources/application.yaml]\n\n== Running JSON to gRPC with a custom filter\n\nThanks to Spring Cloud Gateway flexibility, it is possible to create a custom filter to transform from a JSON payload to\na gRPC message.\n\nEven though it will have a performance impact since we have to serialize and deserialize the requests in the gateway and creating a channel from it,\nit is a common pattern if you want to expose a JSON API while maintaining internal compatibility.\n\nFor that, we can extend our `grpc-json-gateway` to include the `proto` definition with the message we want to send.\n\nimage::grpc-json-gateway.png[grpc-json-gateway]\n\n\nSpring Cloud Gateway contains a mechanism to create custom filters allowing us to intercept requests and add custom logic to them.\n\nFor this particular scenario, we are going to deserialize the JSON request and create a gRPC channel that will send a message to the `grpc-server`.\n\n[source,java]\n----\nstatic class GRPCResponseDecorator extends ServerHttpResponseDecorator {\n\n  @Override\n  public Mono\u003cVoid\u003e writeWith(Publisher\u003c?extends DataBuffer\u003e body) {\n    exchange.getResponse().getHeaders().set(\"Content-Type\", \"application/json\");\n\n    URI requestURI = exchange.getRequest().getURI();\n    ManagedChannel channel = createSecuredChannel(requestURI.getHost(), 6565);\n\n    return getDelegate().writeWith(deserializeJSONRequest()\n            .map(jsonRequest -\u003e {\n                String firstName = jsonRequest.getFirstName();\n                String lastName = jsonRequest.getLastName();\n                return HelloServiceGrpc.newBlockingStub(channel)\n                        .hello(HelloRequest.newBuilder()\n                                .setFirstName(firstName)\n                                .setLastName(lastName)\n                                .build());\n            })\n            .map(this::serialiseJSONResponse)\n            .map(wrapGRPCResponse())\n            .cast(DataBuffer.class)\n            .last());\n  }\n}\n----\n\nThe full implementation can be found\nin: https://github.com/Albertoimpl/spring-cloud-gateway-grpc/blob/5bf80a24a8adf0d5d7c1614524f9d55707536c19/grpc-json-gateway/src/main/java/com/example/grpcserver/hello/JSONToGRPCFilterFactory.java#L38[grpc-json-gateway/src/main/java/com/example/grpcserver/hello/JSONToGRPCFilterFactory.java]\n\nUsing the same `grpc-server`, we can start the gateway with the custom filter with:\n\n[source,shell]\n----\n./gradlew :grpc-json-gateway:bootRun\n----\n\nAnd send JSON requests to the `grpc-json-gateway` using, for example, `curl`:\n\n[source,bash]\n----\ncurl -XPOST 'https://localhost:8091/json/hello' -d '{\"firstName\":\"Duff\",\"lastName\":\"McKagan\"}' -k -H\"Content-Type: application/json\" -v\n----\n\nWe see how the gateway application forwards the requests and returns the JSON payload with the new `Content-Type` header:\n\n[source,bash]\n----\n\u003c HTTP/2 200\n\u003c content-type: application/json\n\u003c content-length: 34\n\u003c\n* Connection #0 to host localhost left intact\n{\"greeting\":\"Hello, Duff McKagan\"}\n----\n\n== Next Steps\n\nIn this post, we've looked at a few examples of how gRPC can be integrated within Spring Cloud Gateway. I’d love to know\nwhat other usages you've found to be helpful in your experiences.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falbertoimpl%2Fspring-cloud-gateway-grpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falbertoimpl%2Fspring-cloud-gateway-grpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falbertoimpl%2Fspring-cloud-gateway-grpc/lists"}