Skip to content

Commit afa7add

Browse files
feat: gRPC support with CallGrpcTaskBuilder and related classes (#1353)
Signed-off-by: Matheus André <matheusandr2@gmail.com>
1 parent 64e52ce commit afa7add

12 files changed

Lines changed: 681 additions & 0 deletions

File tree

fluent/README.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,108 @@ Workflow wf = WorkflowBuilder
6969
> [!NOTE]
7070
> We rename reserved keywords (`for`, `do`, `if`, `while`, `switch`, `try`) to safe identifiers (`forEach`, `tasks`, `when`, etc.).
7171
72+
#### Call Tasks — HTTP, OpenAPI, gRPC
73+
74+
The spec fluent DSL supports all three call task types defined by the specification:
75+
76+
| Call Type | DSL Factory | Shortcut |
77+
|-----------|------------|----------|
78+
| HTTP | `call(http().GET().endpoint(...))` | `DSL.http()` |
79+
| OpenAPI | `call(openapi().document(...).operation(...))` | `DSL.openapi()` |
80+
| gRPC | `call(grpc().proto(...).service(...).method(...))` | `DSL.grpc()` |
81+
82+
**HTTP call:**
83+
84+
```java
85+
import static io.serverlessworkflow.fluent.spec.dsl.DSL.*;
86+
87+
Workflow wf = WorkflowBuilder.workflow("myFlow", "myNs", "1.0")
88+
.tasks(call(
89+
http()
90+
.GET()
91+
.endpoint("https://petstore.swagger.io/v2/pet")
92+
))
93+
.build();
94+
```
95+
96+
**OpenAPI call:**
97+
98+
```java
99+
Workflow wf = WorkflowBuilder.workflow("myFlow", "myNs", "1.0")
100+
.tasks(call(
101+
openapi()
102+
.document("https://api.example.com/openapi.yaml")
103+
.operation("getPetById")
104+
.parameter("id", "42")
105+
))
106+
.build();
107+
```
108+
109+
**gRPC call:**
110+
111+
```java
112+
Workflow wf = WorkflowBuilder.workflow("myFlow", "myNs", "1.0")
113+
.tasks(call(
114+
grpc()
115+
.proto("workflows-samples/grpc/proto/person.proto")
116+
.service("Person", "localhost", 5011)
117+
.method("GetPerson")
118+
))
119+
.build();
120+
```
121+
122+
**gRPC call with arguments and authentication:**
123+
124+
```java
125+
Workflow wf = WorkflowBuilder.workflow("myFlow", "myNs", "1.0")
126+
.tasks(call(
127+
grpc()
128+
.proto("proto/contributors.proto", basic("user", "pass"))
129+
.service("Contributors", "localhost", 5011)
130+
.method("GetContributor")
131+
.argument("github", "${ .github }")
132+
))
133+
.build();
134+
```
135+
136+
**gRPC call with a named task:**
137+
138+
```java
139+
Workflow wf = WorkflowBuilder.workflow("myFlow", "myNs", "1.0")
140+
.tasks(call(
141+
"greet",
142+
grpc()
143+
.proto("proto/person.proto")
144+
.service("Person", "localhost", 5011)
145+
.method("GetPerson")
146+
))
147+
.build();
148+
```
149+
150+
##### `CallGrpcSpec` API Reference
151+
152+
| Method | Description |
153+
|--------|-------------|
154+
| `proto(String uri)` | Sets the proto definition endpoint (file path or URI) |
155+
| `proto(String uri, AuthenticationConfigurer auth)` | Sets the proto endpoint with authentication; also applies the same authentication to the service configuration when no service-level authentication has been set yet |
156+
| `service(String name, String host)` | Sets the gRPC service name and host |
157+
| `service(String name, String host, int port)` | Sets the gRPC service name, host, and port |
158+
| `method(String method)` | Sets the gRPC method name to call |
159+
| `argument(String name, Object value)` | Adds a single method argument |
160+
| `arguments(Map<String, Object> args)` | Adds multiple method arguments |
161+
| `authentication(AuthenticationConfigurer auth)` | Sets or overrides the service-level authentication policy |
162+
163+
You can also use the low-level `CallGrpcConfigurer` lambda directly:
164+
165+
```java
166+
Workflow wf = WorkflowBuilder.workflow("f", "ns", "1")
167+
.tasks(call((CallGrpcConfigurer) b -> b
168+
.proto("proto/service.proto")
169+
.service("Svc", "host")
170+
.method("DoThing")))
171+
.build();
172+
```
173+
72174
---
73175

74176
### 2. Func Fluent

fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/BaseTaskItemListBuilder.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public abstract class BaseTaskItemListBuilder<SELF extends BaseTaskItemListBuild
4545
protected final String TYPE_WAIT = "wait";
4646
protected final String TYPE_HTTP = "http";
4747
protected final String TYPE_OPENAPI = "openapi";
48+
protected final String TYPE_GRPC = "grpc";
4849
protected final String TYPE_WORKFLOW = "workflow";
4950

5051
private final List<TaskItem> list;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.fluent.spec;
17+
18+
import io.serverlessworkflow.api.types.CallGRPC;
19+
import io.serverlessworkflow.api.types.GRPCArguments;
20+
import io.serverlessworkflow.fluent.spec.spi.CallGrpcTaskFluent;
21+
22+
public class CallGrpcTaskBuilder extends TaskBaseBuilder<CallGrpcTaskBuilder>
23+
implements CallGrpcTaskFluent<CallGrpcTaskBuilder> {
24+
25+
CallGrpcTaskBuilder() {
26+
final CallGRPC callGRPC = new CallGRPC();
27+
callGRPC.setWith(new GRPCArguments());
28+
super.setTask(callGRPC);
29+
}
30+
31+
@Override
32+
public CallGrpcTaskBuilder self() {
33+
return this;
34+
}
35+
}

fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/DoTaskBuilder.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ public DoTaskBuilder openapi(String name, Consumer<CallOpenAPITaskBuilder> items
104104
return this;
105105
}
106106

107+
@Override
108+
public DoTaskBuilder grpc(String name, Consumer<CallGrpcTaskBuilder> itemsConfigurer) {
109+
this.listBuilder().grpc(name, itemsConfigurer);
110+
return this;
111+
}
112+
107113
@Override
108114
public DoTaskBuilder workflow(String name, Consumer<WorkflowTaskBuilder> itemsConfigurer) {
109115
this.listBuilder().workflow(name, itemsConfigurer);

fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/TaskItemListBuilder.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,21 @@ public TaskItemListBuilder openapi(
153153
return addTaskItem(new TaskItem(name, task));
154154
}
155155

156+
@Override
157+
public TaskItemListBuilder grpc(String name, Consumer<CallGrpcTaskBuilder> itemsConfigurer) {
158+
name = defaultNameAndRequireConfig(name, itemsConfigurer, TYPE_GRPC);
159+
160+
final CallGrpcTaskBuilder callGRPCBuilder = new CallGrpcTaskBuilder();
161+
itemsConfigurer.accept(callGRPCBuilder);
162+
163+
final CallTask callTask = new CallTask();
164+
callTask.setCallGRPC(callGRPCBuilder.build());
165+
final Task task = new Task();
166+
task.setCallTask(callTask);
167+
168+
return addTaskItem(new TaskItem(name, task));
169+
}
170+
156171
@Override
157172
public TaskItemListBuilder workflow(String name, Consumer<WorkflowTaskBuilder> itemsConfigurer) {
158173
name = defaultNameAndRequireConfig(name, itemsConfigurer, TYPE_WORKFLOW);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.fluent.spec.configurers;
17+
18+
import io.serverlessworkflow.fluent.spec.CallGrpcTaskBuilder;
19+
import java.util.function.Consumer;
20+
21+
@FunctionalInterface
22+
public interface CallGrpcConfigurer extends Consumer<CallGrpcTaskBuilder> {}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.fluent.spec.dsl;
17+
18+
import io.serverlessworkflow.fluent.spec.CallGrpcTaskBuilder;
19+
import io.serverlessworkflow.fluent.spec.configurers.AuthenticationConfigurer;
20+
import io.serverlessworkflow.fluent.spec.configurers.CallGrpcConfigurer;
21+
import io.serverlessworkflow.fluent.spec.spi.CallGrpcTaskFluent;
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
import java.util.Map;
25+
import java.util.function.Consumer;
26+
27+
public final class CallGrpcSpec implements CallGrpcConfigurer {
28+
29+
private final List<Consumer<CallGrpcTaskFluent<?>>> steps = new ArrayList<>();
30+
31+
public CallGrpcSpec proto(String uri) {
32+
steps.add(b -> b.proto(uri));
33+
return this;
34+
}
35+
36+
public CallGrpcSpec proto(String uri, AuthenticationConfigurer authenticationConfigurer) {
37+
steps.add(b -> b.proto(uri, authenticationConfigurer));
38+
return this;
39+
}
40+
41+
public CallGrpcSpec service(String name, String host) {
42+
steps.add(b -> b.service(name, host));
43+
return this;
44+
}
45+
46+
public CallGrpcSpec service(String name, String host, int port) {
47+
steps.add(b -> b.service(name, host, port));
48+
return this;
49+
}
50+
51+
public CallGrpcSpec method(String method) {
52+
steps.add(b -> b.method(method));
53+
return this;
54+
}
55+
56+
public CallGrpcSpec arguments(Map<String, Object> arguments) {
57+
steps.add(b -> b.arguments(arguments));
58+
return this;
59+
}
60+
61+
public CallGrpcSpec argument(String name, Object value) {
62+
steps.add(b -> b.argument(name, value));
63+
return this;
64+
}
65+
66+
public CallGrpcSpec authentication(AuthenticationConfigurer authenticationConfigurer) {
67+
steps.add(b -> b.authentication(authenticationConfigurer));
68+
return this;
69+
}
70+
71+
@Override
72+
public void accept(CallGrpcTaskBuilder builder) {
73+
for (var s : steps) {
74+
s.accept(builder);
75+
}
76+
}
77+
}

fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/dsl/DSL.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import io.serverlessworkflow.fluent.spec.TimeoutBuilder;
2727
import io.serverlessworkflow.fluent.spec.TryTaskBuilder;
2828
import io.serverlessworkflow.fluent.spec.configurers.AuthenticationConfigurer;
29+
import io.serverlessworkflow.fluent.spec.configurers.CallGrpcConfigurer;
2930
import io.serverlessworkflow.fluent.spec.configurers.CallHttpConfigurer;
3031
import io.serverlessworkflow.fluent.spec.configurers.CallOpenAPIConfigurer;
3132
import io.serverlessworkflow.fluent.spec.configurers.ForEachConfigurer;
@@ -106,6 +107,10 @@ public static CallOpenAPISpec openapi() {
106107
return new CallOpenAPISpec();
107108
}
108109

110+
public static CallGrpcSpec grpc() {
111+
return new CallGrpcSpec();
112+
}
113+
109114
public static WorkflowSpec workflow(String namespace, String name, String version) {
110115
return new WorkflowSpec().namespace(namespace).name(name).version(version);
111116
}
@@ -683,6 +688,14 @@ public static TasksConfigurer call(String name, CallOpenAPIConfigurer configurer
683688
return list -> list.openapi(name, configurer);
684689
}
685690

691+
public static TasksConfigurer call(CallGrpcConfigurer configurer) {
692+
return list -> list.grpc(configurer);
693+
}
694+
695+
public static TasksConfigurer call(String name, CallGrpcConfigurer configurer) {
696+
return list -> list.grpc(name, configurer);
697+
}
698+
686699
/**
687700
* Create a {@link TasksConfigurer} that adds a {@code set} task using a low-level configurer.
688701
*
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.fluent.spec.spi;
17+
18+
import io.serverlessworkflow.fluent.spec.TaskBaseBuilder;
19+
import java.util.function.Consumer;
20+
21+
public interface CallGrpcFluent<SELF extends TaskBaseBuilder<SELF>, LIST> {
22+
23+
LIST grpc(String name, Consumer<SELF> itemsConfigurer);
24+
25+
default LIST grpc(Consumer<SELF> itemsConfigurer) {
26+
return this.grpc(null, itemsConfigurer);
27+
}
28+
}

0 commit comments

Comments
 (0)