forked from quarkusio/quarkus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
323774b
commit 2fb227c
Showing
45 changed files
with
2,665 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
//// | ||
This guide is maintained in the main Quarkus repository | ||
and pull requests should be submitted there: | ||
https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc | ||
//// | ||
= Using gRPC Transcoding | ||
include::_attributes.adoc[] | ||
:categories: serialization | ||
:summary: This page explains how to enable gRPC Transcoding in your Quarkus application for RESTful interactions with gRPC services. | ||
:topics: grpc, transcoding, rest, json | ||
:extensions: io.quarkus:quarkus-grpc | ||
|
||
gRPC Transcoding lets you expose your gRPC services as RESTful JSON endpoints. | ||
This is particularly useful in these scenarios: | ||
|
||
1. **Client-side limitations:** When you need to interact with gRPC services from environments (like web browsers) that don't directly support gRPC. | ||
2. **Simplified local development:** While services like Google Cloud Run and Google Cloud Endpoints offer built-in gRPC transcoding, replicating this locally often requires setting up a proxy like Envoy. Transcoding directly within your Quarkus application streamlines your development process. | ||
== Configuring Your Project | ||
|
||
First, add the `quarkus-grpc` extension to your project: | ||
|
||
[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] | ||
.pom.xml | ||
---- | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-grpc</artifactId> | ||
</dependency> | ||
---- | ||
|
||
[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] | ||
.build.gradle | ||
---- | ||
implementation("io.quarkus:quarkus-grpc") | ||
---- | ||
|
||
== Transcoding configuration | ||
|
||
include::{generated-dir}/config/quarkus-grpc-transcoding-config-grpc-transcoding-config.adoc[opts=optional,leveloffset=+1] | ||
|
||
== Example | ||
|
||
Let's imagine you have a gRPC service defined. | ||
Here's an example of a simple service: | ||
|
||
[source,protobuf] | ||
---- | ||
syntax = "proto3"; | ||
import "google/api/annotations.proto"; //<1> | ||
option java_multiple_files = true; | ||
option java_package = "examples"; | ||
option java_outer_classname = "HelloWorldProto"; | ||
option objc_class_prefix = "HLW"; | ||
package helloworld; | ||
// The greeting service definition. | ||
service Greeter { | ||
// RPC with simple path | ||
rpc SimplePath (HelloRequest) returns (HelloReply) { | ||
option (google.api.http) = { //<2> | ||
post: "/v1/simple" | ||
body: "*" | ||
}; | ||
} | ||
} | ||
message HelloRequest { | ||
string name = 1; | ||
} | ||
message HelloReply { | ||
string message = 1; | ||
} | ||
---- | ||
|
||
<1> We need to import the `google/api/annotations.proto` file so that we can use the `google.api.http` option. | ||
<2> This option is used to define the RESTful path for the gRPC service. | ||
|
||
Now we need to implement the service: | ||
|
||
[source,java] | ||
---- | ||
@GrpcService | ||
public class HelloWorldNewService implements Greeter { | ||
@Override | ||
public Uni<HelloReply> simplePath(HelloRequest request) { | ||
return Uni.createFrom().item(HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()); | ||
} | ||
} | ||
---- | ||
|
||
To enable gRPC Transcoding, you need to add the following configuration to your `application.properties` file: | ||
|
||
[source,properties] | ||
---- | ||
quarkus.grpc.transcoding.enabled=true | ||
---- | ||
|
||
Now you can access the gRPC service through a RESTful JSON interface. | ||
For example, you can use the following `curl` command: | ||
|
||
[source,shell] | ||
---- | ||
curl -X POST http://localhost:8080/v1/simple -H "Content-Type: application/json" -d '{"name": "World"}' | ||
---- | ||
|
||
This command should return response similar to the following: | ||
|
||
[source,json] | ||
---- | ||
{ | ||
"message": "Hello World" | ||
} | ||
---- | ||
|
||
== Advanced Usage | ||
|
||
While the above example demonstrates a simple use case, gRPC Transcoding can be configured in more complex scenarios. | ||
For example, you can define paths with variables, query parameters, and more. | ||
|
||
For example you can define methods with path variables: | ||
|
||
[source,protobuf] | ||
---- | ||
service Greeter { | ||
rpc PathWithVariable (HelloRequest) returns (HelloReply) { | ||
option (google.api.http) = { | ||
post: "/v1/path/{name}" //<1> | ||
body: "*" | ||
}; | ||
} | ||
} | ||
message HelloRequest { | ||
string name = 1; //<2> | ||
} | ||
---- | ||
|
||
<1> The path variable is defined using curly braces. | ||
<2> The `name` field is used to define the path variable. | ||
|
||
Now if you send a request to the `/v1/path/World` path, like this: | ||
|
||
[source,shell] | ||
---- | ||
curl -X POST http://localhost:8080/v1/path/World | ||
---- | ||
|
||
You should receive a response similar to the following: | ||
|
||
[source,json] | ||
---- | ||
{ | ||
"message": "Hello World" | ||
} | ||
---- | ||
|
||
**Important Notes:** | ||
|
||
* You also should consult https://cloud.google.com/endpoints/docs/grpc/transcoding[google's documentation on gRPC transcoding] for more information. | ||
* Consider whether you need a proxy like Envoy for advanced transcoding and routing. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
extensions/grpc/api/src/main/java/io/quarkus/grpc/GrpcTranscoding.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package io.quarkus.grpc; | ||
|
||
import com.google.protobuf.Message; | ||
|
||
public interface GrpcTranscoding { | ||
|
||
String getGrpcServiceName(); | ||
|
||
<Req extends Message, Resp extends Message> GrpcTranscodingDescriptor<Req, Resp> findTranscodingDescriptor( | ||
String methodName); | ||
} |
21 changes: 21 additions & 0 deletions
21
extensions/grpc/api/src/main/java/io/quarkus/grpc/GrpcTranscodingDescriptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package io.quarkus.grpc; | ||
|
||
public class GrpcTranscodingDescriptor<Req extends com.google.protobuf.Message, Resp extends com.google.protobuf.Message> { | ||
|
||
private final GrpcTranscodingMarshaller<Req> requestMarshaller; | ||
private final GrpcTranscodingMarshaller<Resp> responseMarshaller; | ||
|
||
public GrpcTranscodingDescriptor(GrpcTranscodingMarshaller<Req> requestMarshaller, | ||
GrpcTranscodingMarshaller<Resp> responseMarshaller) { | ||
this.requestMarshaller = requestMarshaller; | ||
this.responseMarshaller = responseMarshaller; | ||
} | ||
|
||
public GrpcTranscodingMarshaller<Req> getRequestMarshaller() { | ||
return requestMarshaller; | ||
} | ||
|
||
public GrpcTranscodingMarshaller<Resp> getResponseMarshaller() { | ||
return responseMarshaller; | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
extensions/grpc/api/src/main/java/io/quarkus/grpc/GrpcTranscodingMarshaller.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package io.quarkus.grpc; | ||
|
||
import static com.google.common.base.Preconditions.checkNotNull; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
import org.jboss.logging.Logger; | ||
|
||
import com.google.protobuf.InvalidProtocolBufferException; | ||
import com.google.protobuf.Message; | ||
import com.google.protobuf.util.JsonFormat; | ||
|
||
import io.grpc.MethodDescriptor; | ||
import io.grpc.Status; | ||
|
||
public class GrpcTranscodingMarshaller<T extends Message> implements MethodDescriptor.PrototypeMarshaller<T> { | ||
|
||
private final static Logger log = Logger.getLogger(GrpcTranscodingMarshaller.class); | ||
|
||
private final T defaultInstance; | ||
|
||
public GrpcTranscodingMarshaller(T defaultInstance) { | ||
this.defaultInstance = checkNotNull(defaultInstance, "defaultInstance cannot be null"); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public Class<T> getMessageClass() { | ||
return (Class<T>) defaultInstance.getClass(); | ||
} | ||
|
||
@Override | ||
public T getMessagePrototype() { | ||
return defaultInstance; | ||
} | ||
|
||
@Override | ||
public InputStream stream(T value) { | ||
try { | ||
String response = JsonFormat.printer().omittingInsignificantWhitespace().print(value); | ||
return new ByteArrayInputStream(response.getBytes(StandardCharsets.UTF_8)); | ||
} catch (InvalidProtocolBufferException e) { | ||
throw Status.INTERNAL.withDescription("Unable to convert message to JSON").withCause(e).asRuntimeException(); | ||
} | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public T parse(InputStream stream) { | ||
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) { | ||
Message.Builder builder = defaultInstance.newBuilderForType(); | ||
JsonFormat.parser().ignoringUnknownFields().merge(reader, builder); | ||
return (T) builder.build(); | ||
} catch (InvalidProtocolBufferException e) { | ||
log.error("Unable to parse JSON to message", e); | ||
throw Status.INTERNAL.withDescription("Unable to parse JSON to message").withCause(e).asRuntimeException(); | ||
} catch (IOException e) { | ||
log.error("An I/O error occurred while parsing the stream", e); | ||
throw Status.INTERNAL.withDescription("An I/O error occurred while parsing the stream").withCause(e) | ||
.asRuntimeException(); | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
extensions/grpc/api/src/main/java/io/quarkus/grpc/GrpcTranscodingMethod.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package io.quarkus.grpc; | ||
|
||
import static java.lang.annotation.ElementType.METHOD; | ||
|
||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target(METHOD) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface GrpcTranscodingMethod { | ||
|
||
String grpcMethodName(); | ||
|
||
String httpMethod(); | ||
|
||
String httpPath(); | ||
} |
Oops, something went wrong.