diff --git a/spring-cloud-function-grpc/README.md b/spring-cloud-function-grpc/README.md
index e53c02f68..7991ad4f2 100644
--- a/spring-cloud-function-grpc/README.md
+++ b/spring-cloud-function-grpc/README.md
@@ -1,8 +1,77 @@
### Introduction
-Spring Cloud Function allows you to invoke function via [gRPC](https://grpc.io/).
+Spring Cloud Function allows you to invoke function via [gRPC](https://grpc.io/). While you can read more about gRPC in te provided link, this section will describe the parts relevant to Spring Cloud Function integration.
-TBD
+As with all other Spring-boot based frameworks all you need to do is add `spring-cloud-function-grpc` dependency to your POM.
+```xml
+
+ org.springframework.cloud
+ spring-cloud-function-grpc
+ ${current.version}
+
+```
### Programming model
-TBD
\ No newline at end of file
+Spring Cloud Function gRPC support provides two modes of operation - _client_ and _server_. In other words when you add `spring-cloud-function-grpc` dependency to your POM you may or may not want the gRPC server as you may
+only be interested in client-side utilities to invoke a function exposed via gRPC server running on some host/port.
+To support these two modes Spring Cloud Function provides `spring.cloud.function.grpc.server` which defaults to `true`.
+This means that the default mode of operation is _server_, since the core imtention of gRPC support is to expose user Function via gRPC. However, if you're only inteersted in using client-side utilities (e.g., `GrpcUtils` to help to invoke a function or convert `GrpcMessage` to Spring `Message` and vice versa), you can set this property to `false`.
+Hoever if you intention is to
+
+
+At the center of gRPC and Spring Cloud Function integration is a canonical protobuff structure - `GrpcMessage`. It is modeled after Spring [Message](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/messaging/Message.html).
+
+```
+message GrpcMessage {
+ bytes payload = 1;
+ map headers = 2;
+}
+```
+As you can see it is a very generic structure which can support any type of data amd metadata you wish to exchange.
+
+It alos defines a `MessagingService` allowing you to generate required stubs to support true plolyglot nature of gRPC.
+```
+service MessagingService {
+ rpc biStream(stream GrpcMessage) returns (stream GrpcMessage);
+
+ rpc clientStream(stream GrpcMessage) returns (GrpcMessage);
+
+ rpc serverStream(GrpcMessage) returns (stream GrpcMessage);
+
+ rpc requestReply(GrpcMessage) returns (GrpcMessage);
+}
+```
+That said, when using Java, you do not need to generate anything, rather identify function definition and send and receive Spring `Messages`.
+You can get a pretty good idea from this [test case](https://github.com/spring-cloud/spring-cloud-function/blob/82e2583acd7c8aaaf2bc5ec935d486a336e97ae7/spring-cloud-function-grpc/src/test/java/org/springframework/cloud/function/grpc/GrpcInteractionTests.java#L49).
+
+#### 4 Interaction Modes
+
+The gRPC provides 4 interaction modes
+* Reques/Repply
+* Server-side streaming
+* Client-side streaming
+* Bi-directional streaming
+
+Spring Cloud Function provides support for all 4 of them.
+
+
+##### Request Reply
+The most straight forward interaction mode is _Request/Reply_.
+Suppose you have a function
+
+```java
+@EnableAutoConfiguration
+public static class SampleConfiguration {
+ @Bean
+ public Function uppercase() {
+ return v -> v.toUpperCase();
+ }
+}
+```
+You can invoke it using utility method(s) provided in `GrpcUtils` class
+```java
+Message message = MessageBuilder.withPayload("\"hello gRPC\"".getBytes())
+ .setHeader("foo", "bar")
+ .build();
+Message reply = GrpcUtils.requestReply(message);
+```
\ No newline at end of file
diff --git a/spring-cloud-function-grpc/src/main/java/org/springframework/cloud/function/grpc/GrpcAutoConfiguration.java b/spring-cloud-function-grpc/src/main/java/org/springframework/cloud/function/grpc/GrpcAutoConfiguration.java
index 677cc61ba..65fb5abc5 100644
--- a/spring-cloud-function-grpc/src/main/java/org/springframework/cloud/function/grpc/GrpcAutoConfiguration.java
+++ b/spring-cloud-function-grpc/src/main/java/org/springframework/cloud/function/grpc/GrpcAutoConfiguration.java
@@ -31,7 +31,7 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(FunctionGrpcProperties.class)
-@ConditionalOnProperty(name = "spring.cloud.function.grpc.mode", havingValue = "server", matchIfMissing = false)
+@ConditionalOnProperty(name = "spring.cloud.function.grpc.server", havingValue = "true", matchIfMissing = true)
class GrpcAutoConfiguration {
@Bean
diff --git a/spring-cloud-function-grpc/src/test/java/org/springframework/cloud/function/grpc/GrpcInteractionTests.java b/spring-cloud-function-grpc/src/test/java/org/springframework/cloud/function/grpc/GrpcInteractionTests.java
index b49ae1a6c..1014708ad 100644
--- a/spring-cloud-function-grpc/src/test/java/org/springframework/cloud/function/grpc/GrpcInteractionTests.java
+++ b/spring-cloud-function-grpc/src/test/java/org/springframework/cloud/function/grpc/GrpcInteractionTests.java
@@ -51,8 +51,7 @@ public class GrpcInteractionTests {
SampleConfiguration.class).web(WebApplicationType.NONE).run(
"--spring.jmx.enabled=false",
"--spring.cloud.function.definition=uppercase",
- "--spring.cloud.function.grpc.port=" + FunctionGrpcProperties.GRPC_PORT,
- "--spring.cloud.function.grpc.mode=server")) {
+ "--spring.cloud.function.grpc.port=" + FunctionGrpcProperties.GRPC_PORT)) {
Message message = MessageBuilder.withPayload("\"hello gRPC\"".getBytes())
.setHeader("foo", "bar")
@@ -72,8 +71,7 @@ public class GrpcInteractionTests {
"--spring.jmx.enabled=false",
"--spring.cloud.function.definition=uppercase",
"--spring.cloud.function.grpc.port="
- + FunctionGrpcProperties.GRPC_PORT,
- "--spring.cloud.function.grpc.mode=server")) {
+ + FunctionGrpcProperties.GRPC_PORT)) {
List> messages = new ArrayList<>();
messages.add(MessageBuilder.withPayload("\"Ricky\"".getBytes()).setHeader("foo", "bar")
@@ -104,8 +102,7 @@ public class GrpcInteractionTests {
"--spring.jmx.enabled=false",
"--spring.cloud.function.definition=uppercaseReactive",
"--spring.cloud.function.grpc.port="
- + FunctionGrpcProperties.GRPC_PORT,
- "--spring.cloud.function.grpc.mode=server")) {
+ + FunctionGrpcProperties.GRPC_PORT)) {
List> messages = new ArrayList<>();
messages.add(MessageBuilder.withPayload("\"Ricky\"".getBytes()).setHeader("foo", "bar")
@@ -136,8 +133,7 @@ public class GrpcInteractionTests {
"--spring.jmx.enabled=false",
"--spring.cloud.function.definition=streamInStringOut",
"--spring.cloud.function.grpc.port="
- + FunctionGrpcProperties.GRPC_PORT,
- "--spring.cloud.function.grpc.mode=server")) {
+ + FunctionGrpcProperties.GRPC_PORT)) {
List> messages = new ArrayList<>();
messages.add(MessageBuilder.withPayload("\"Ricky\"".getBytes()).setHeader("foo", "bar")
@@ -161,8 +157,7 @@ public class GrpcInteractionTests {
"--spring.jmx.enabled=false",
"--spring.cloud.function.definition=stringInStreamOut",
"--spring.cloud.function.grpc.port="
- + FunctionGrpcProperties.GRPC_PORT,
- "--spring.cloud.function.grpc.mode=server")) {
+ + FunctionGrpcProperties.GRPC_PORT)) {
Message message = MessageBuilder.withPayload("\"Ricky\"".getBytes()).setHeader("foo", "bar").build();
@@ -183,8 +178,7 @@ public class GrpcInteractionTests {
"--spring.jmx.enabled=false",
"--spring.cloud.function.definition=streamInStringOut",
"--spring.cloud.function.grpc.port="
- + FunctionGrpcProperties.GRPC_PORT,
- "--spring.cloud.function.grpc.mode=server")) {
+ + FunctionGrpcProperties.GRPC_PORT)) {
List> messages = new ArrayList<>();
messages.add(MessageBuilder.withPayload("\"Ricky\"".getBytes()).setHeader("foo", "bar")
@@ -214,8 +208,7 @@ public class GrpcInteractionTests {
"--spring.jmx.enabled=false",
"--spring.cloud.function.definition=stringInStreamOut",
"--spring.cloud.function.grpc.port="
- + FunctionGrpcProperties.GRPC_PORT,
- "--spring.cloud.function.grpc.mode=server")) {
+ + FunctionGrpcProperties.GRPC_PORT)) {
List> messages = new ArrayList<>();
messages.add(MessageBuilder.withPayload("\"Ricky\"".getBytes()).setHeader("foo", "bar")