Skip to content

Commit 4062fc4

Browse files
authored
Refactor how endpoint and authentication are handled in the fluent API (#1319)
Signed-off-by: Matheus Cruz <matheuscruz.dev@gmail.com>
1 parent 3dfd814 commit 4062fc4

9 files changed

Lines changed: 278 additions & 58 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,7 @@ target/
2929
build/
3030

3131
### VS Code ###
32-
.vscode/
32+
.vscode/
33+
34+
# Bob-Shell
35+
.bob/notes/

experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLTest.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,13 @@ void get_named_with_authentication_uses_auth_policy() {
266266
assertEquals("GET", http.getWith().getMethod());
267267
assertEquals(
268268
"http://service/api/users",
269-
http.getWith().getEndpoint().getUriTemplate().getLiteralUri().toString(),
269+
http.getWith()
270+
.getEndpoint()
271+
.getEndpointConfiguration()
272+
.getUri()
273+
.getLiteralEndpointURI()
274+
.getLiteralUri()
275+
.toString(),
270276
"endpoint should be set from get(name, endpoint, auth)");
271277

272278
assertNotNull(
@@ -304,7 +310,13 @@ void get_with_uri_and_authentication() {
304310
assertEquals("GET", http.getWith().getMethod());
305311
assertEquals(
306312
endpoint.toString(),
307-
http.getWith().getEndpoint().getUriTemplate().getLiteralUri().toString(),
313+
http.getWith()
314+
.getEndpoint()
315+
.getEndpointConfiguration()
316+
.getUri()
317+
.getLiteralEndpointURI()
318+
.getLiteralUri()
319+
.toString(),
308320
"endpoint should be derived from URI");
309321

310322
assertNotNull(http.getWith().getEndpoint().getEndpointConfiguration().getAuthentication());
@@ -371,7 +383,13 @@ void post_named_with_authentication() {
371383
assertEquals("POST", http.getWith().getMethod());
372384
assertEquals(
373385
"https://orders.example.com/api/orders",
374-
http.getWith().getEndpoint().getUriTemplate().getLiteralUri().toString());
386+
http.getWith()
387+
.getEndpoint()
388+
.getEndpointConfiguration()
389+
.getUri()
390+
.getLiteralEndpointURI()
391+
.getLiteralUri()
392+
.toString());
375393
assertEquals(body, http.getWith().getBody());
376394

377395
assertNotNull(http.getWith().getEndpoint().getEndpointConfiguration().getAuthentication());
@@ -409,7 +427,13 @@ void call_with_preconfigured_http_spec() {
409427
assertEquals("POST", http.getWith().getMethod());
410428
assertEquals(
411429
"http://service/api",
412-
http.getWith().getEndpoint().getUriTemplate().getLiteralUri().toString());
430+
http.getWith()
431+
.getEndpoint()
432+
.getEndpointConfiguration()
433+
.getUri()
434+
.getLiteralEndpointURI()
435+
.getLiteralUri()
436+
.toString());
413437
assertEquals(
414438
"svc-auth",
415439
http.getWith()

experimental/test/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@
7171
<dependency>
7272
<groupId>io.serverlessworkflow</groupId>
7373
<artifactId>serverlessworkflow-impl-jq</artifactId>
74+
<scope>test</scope>
75+
</dependency>
76+
<dependency>
77+
<groupId>io.serverlessworkflow</groupId>
78+
<artifactId>serverlessworkflow-impl-openapi</artifactId>
79+
<version>${project.version}</version>
80+
<scope>test</scope>
7481
</dependency>
7582
<dependency>
7683
<groupId>org.glassfish.jersey.media</groupId>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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.test;
17+
18+
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.openapi;
19+
20+
import io.serverlessworkflow.fluent.func.FuncWorkflowBuilder;
21+
import io.serverlessworkflow.impl.WorkflowApplication;
22+
import io.serverlessworkflow.impl.WorkflowDefinition;
23+
import io.serverlessworkflow.impl.WorkflowInstance;
24+
import io.serverlessworkflow.impl.WorkflowModel;
25+
import java.io.IOException;
26+
import java.net.URI;
27+
import java.util.Map;
28+
import mockwebserver3.MockResponse;
29+
import mockwebserver3.MockWebServer;
30+
import okhttp3.Headers;
31+
import org.assertj.core.api.SoftAssertions;
32+
import org.junit.jupiter.api.AfterEach;
33+
import org.junit.jupiter.api.BeforeEach;
34+
import org.junit.jupiter.api.Test;
35+
36+
public class FuncOpenAPITest {
37+
38+
private static MockWebServer mockWebServer;
39+
40+
@BeforeEach
41+
public void setup() throws IOException {
42+
mockWebServer = new MockWebServer();
43+
mockWebServer.start(0);
44+
}
45+
46+
@AfterEach
47+
public void tearDown() {
48+
mockWebServer.close();
49+
}
50+
51+
@Test
52+
void test_openapi_document_with_non_jq_uri_string() {
53+
String mockedSwaggerDoc =
54+
"""
55+
{
56+
"swagger": "2.0",
57+
"info": { "version": "1.0.0", "title": "Mock Petstore" },
58+
"host": "localhost:%d",
59+
"basePath": "/v2",
60+
"schemes": [ "http" ],
61+
"paths": {
62+
"/pet/findByStatus": {
63+
"get": {
64+
"operationId": "findPetsByStatus",
65+
"parameters": [
66+
{
67+
"name": "status",
68+
"in": "query",
69+
"required": true,
70+
"type": "string"
71+
}
72+
],
73+
"responses": { "200": { "description": "OK" } }
74+
}
75+
}
76+
}
77+
}
78+
"""
79+
.formatted(mockWebServer.getPort());
80+
81+
mockWebServer.enqueue(
82+
new MockResponse(200, Headers.of("Content-Type", "application/json"), mockedSwaggerDoc));
83+
mockWebServer.enqueue(
84+
new MockResponse(
85+
200,
86+
Headers.of("Content-Type", "application/json"),
87+
"""
88+
{ "description": "OK" }
89+
"""));
90+
var w =
91+
FuncWorkflowBuilder.workflow("openapi-call-workflow")
92+
.tasks(
93+
openapi()
94+
.document(URI.create(mockWebServer.url("/v2/swagger.json").toString()))
95+
.operation("findPetsByStatus")
96+
.parameters(Map.of("status", "available")))
97+
.build();
98+
99+
try (WorkflowApplication app = WorkflowApplication.builder().build()) {
100+
101+
WorkflowDefinition def = app.workflowDefinition(w);
102+
WorkflowInstance instance = def.instance(Map.of());
103+
WorkflowModel model = instance.start().join();
104+
105+
SoftAssertions.assertSoftly(
106+
softly -> {
107+
softly.assertThat(model).isNotNull();
108+
softly.assertThat(model.asMap()).contains(Map.of("description", "OK"));
109+
});
110+
}
111+
}
112+
}

fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/spi/CallHttpTaskFluent.java

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,57 +50,89 @@ default SELF method(String method) {
5050
return self();
5151
}
5252

53+
/**
54+
* Sets the endpoint URI for the HTTP call.
55+
*
56+
* @param endpoint the URI to call
57+
* @return this builder instance for method chaining
58+
*/
5359
default SELF endpoint(URI endpoint) {
5460
((CallHTTP) this.self().getTask())
5561
.getWith()
5662
.setEndpoint(new Endpoint().withUriTemplate(new UriTemplate().withLiteralUri(endpoint)));
5763
return self();
5864
}
5965

66+
/**
67+
* Sets the endpoint URI for the HTTP call with authentication configuration.
68+
*
69+
* @param endpoint the URI to call
70+
* @param auth consumer to configure authentication policy
71+
* @return this builder instance for method chaining
72+
*/
6073
default SELF endpoint(URI endpoint, Consumer<ReferenceableAuthenticationPolicyBuilder> auth) {
6174
final ReferenceableAuthenticationPolicyBuilder policy =
6275
new ReferenceableAuthenticationPolicyBuilder();
63-
final UriTemplate uriTemplate = new UriTemplate().withLiteralUri(endpoint);
6476
auth.accept(policy);
6577
((CallHTTP) this.self().getTask())
6678
.getWith()
6779
.setEndpoint(
6880
new Endpoint()
6981
.withEndpointConfiguration(
7082
new EndpointConfiguration()
71-
.withUri(new EndpointUri().withLiteralEndpointURI(uriTemplate))
72-
.withAuthentication(policy.build()))
73-
.withUriTemplate(uriTemplate));
83+
.withUri(
84+
new EndpointUri()
85+
.withLiteralEndpointURI(new UriTemplate().withLiteralUri(endpoint)))
86+
.withAuthentication(policy.build())));
7487
return self();
7588
}
7689

90+
/**
91+
* Sets the endpoint using a runtime expression or URI string.
92+
*
93+
* @param expr the runtime expression or URI string for the endpoint
94+
* @return this builder instance for method chaining
95+
*/
7796
default SELF endpoint(String expr) {
7897
((CallHTTP) this.self().getTask()).getWith().setEndpoint(EndpointUtil.fromString(expr));
7998
return self();
8099
}
81100

101+
/**
102+
* Sets the endpoint using a runtime expression or URI string with authentication configuration.
103+
*
104+
* @param expr the runtime expression or URI string for the endpoint
105+
* @param auth consumer to configure authentication policy
106+
* @return this builder instance for method chaining
107+
*/
82108
default SELF endpoint(String expr, Consumer<ReferenceableAuthenticationPolicyBuilder> auth) {
83109
final ReferenceableAuthenticationPolicyBuilder policy =
84110
new ReferenceableAuthenticationPolicyBuilder();
85111
auth.accept(policy);
86112

87-
final Endpoint endpoint = EndpointUtil.fromString(expr);
88-
endpoint.setEndpointConfiguration(
89-
new EndpointConfiguration().withAuthentication(policy.build()));
90-
91-
((CallHTTP) this.self().getTask()).getWith().setEndpoint(endpoint);
113+
((CallHTTP) this.self().getTask())
114+
.getWith()
115+
.setEndpoint(EndpointUtil.fromString(expr, policy.build()));
92116
return self();
93117
}
94118

119+
/**
120+
* Sets the endpoint using a runtime expression or URI string with authentication policy
121+
* reference.
122+
*
123+
* @param expr the runtime expression or URI string for the endpoint
124+
* @param authUse the name of the authentication policy to reference
125+
* @return this builder instance for method chaining
126+
*/
95127
default SELF endpoint(String expr, String authUse) {
96-
final Endpoint endpoint = EndpointUtil.fromString(expr);
97-
endpoint.withEndpointConfiguration(
98-
new EndpointConfiguration()
99-
.withAuthentication(
128+
((CallHTTP) this.self().getTask())
129+
.getWith()
130+
.setEndpoint(
131+
EndpointUtil.fromString(
132+
expr,
100133
new ReferenceableAuthenticationPolicy()
101134
.withAuthenticationPolicyReference(
102135
new AuthenticationPolicyReference(authUse))));
103-
((CallHTTP) this.self().getTask()).getWith().setEndpoint(endpoint);
104136
return self();
105137
}
106138

fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/spi/CallOpenAPITaskFluent.java

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.serverlessworkflow.api.types.EndpointUri;
2222
import io.serverlessworkflow.api.types.ExternalResource;
2323
import io.serverlessworkflow.api.types.OpenAPIArguments;
24+
import io.serverlessworkflow.api.types.ReferenceableAuthenticationPolicy;
2425
import io.serverlessworkflow.api.types.UriTemplate;
2526
import io.serverlessworkflow.fluent.spec.ReferenceableAuthenticationPolicyBuilder;
2627
import io.serverlessworkflow.fluent.spec.TaskBaseBuilder;
@@ -40,11 +41,19 @@ default CallOpenAPI build() {
4041

4142
SELF self();
4243

44+
/**
45+
* Sets the OpenAPI document location. This method automatically detects whether the provided
46+
* string is a literal URI or a JQ runtime expression.
47+
*
48+
* @param uri the OpenAPI document location as either a literal URI string or a JQ expression
49+
* @return this builder instance for method chaining
50+
* @see #document(URI) for setting a literal URI directly
51+
* @see #document(String, AuthenticationConfigurer) for setting a document with authentication
52+
*/
4353
default SELF document(String uri) {
4454
((CallOpenAPI) this.self().getTask())
4555
.getWith()
46-
.withDocument(
47-
new ExternalResource().withEndpoint(new Endpoint().withRuntimeExpression(uri)));
56+
.setDocument(new ExternalResource().withEndpoint(EndpointUtil.fromString(uri)));
4857
return self();
4958
}
5059

@@ -62,41 +71,33 @@ default SELF document(String uri, AuthenticationConfigurer authenticationConfigu
6271
final ReferenceableAuthenticationPolicyBuilder policy =
6372
new ReferenceableAuthenticationPolicyBuilder();
6473
authenticationConfigurer.accept(policy);
65-
((CallOpenAPI) this.self().getTask()).getWith().setAuthentication(policy.build());
74+
ReferenceableAuthenticationPolicy auth = policy.build();
75+
((CallOpenAPI) this.self().getTask()).getWith().setAuthentication(auth);
6676
((CallOpenAPI) this.self().getTask())
6777
.getWith()
68-
.setDocument(
69-
new ExternalResource()
70-
.withEndpoint(
71-
new Endpoint()
72-
.withRuntimeExpression(uri)
73-
.withEndpointConfiguration(
74-
new EndpointConfiguration()
75-
.withUri(new EndpointUri().withExpressionEndpointURI(uri))
76-
.withAuthentication(policy.build()))));
78+
.setDocument(new ExternalResource().withEndpoint(EndpointUtil.fromString(uri, auth)));
7779
return self();
7880
}
7981

8082
default SELF document(URI uri, AuthenticationConfigurer authenticationConfigurer) {
8183
final ReferenceableAuthenticationPolicyBuilder policy =
8284
new ReferenceableAuthenticationPolicyBuilder();
8385
authenticationConfigurer.accept(policy);
84-
85-
((CallOpenAPI) this.self().getTask()).getWith().setAuthentication(policy.build());
86+
ReferenceableAuthenticationPolicy auth = policy.build();
87+
((CallOpenAPI) this.self().getTask()).getWith().setAuthentication(auth);
8688
((CallOpenAPI) this.self().getTask())
8789
.getWith()
8890
.setDocument(
8991
new ExternalResource()
9092
.withEndpoint(
9193
new Endpoint()
92-
.withUriTemplate(new UriTemplate().withLiteralUri(uri))
9394
.withEndpointConfiguration(
9495
new EndpointConfiguration()
9596
.withUri(
9697
new EndpointUri()
9798
.withLiteralEndpointURI(
9899
new UriTemplate().withLiteralUri(uri)))
99-
.withAuthentication(policy.build()))));
100+
.withAuthentication(auth))));
100101
return self();
101102
}
102103

0 commit comments

Comments
 (0)