Skip to content

Commit cd046db

Browse files
committed
Add automatic URI detection for OpenAPI document configuration
- Enhanced CallOpenAPITaskFluent.document(String) to automatically detect whether the input is a literal URI or a JQ runtime expression - Added EndpointUtil.isJqExpr() helper method to identify JQ expressions (strings starting with "${" ) - Added comprehensive test coverage with FuncOpenAPITest using MockWebServer - Added serverlessworkflow-impl-openapi dependency to experimental/test module - Updated .gitignore to exclude Bob-Shell notes directory The document() method now intelligently handles both: - Literal URI strings (e.g., "http://example.com/swagger.json") - JQ runtime expressions (e.g., "${.openapi.url}") This improves the developer experience by eliminating the need to choose between document(String) and document(URI) methods based on the input type. Closes #1303 Signed-off-by: Matheus Cruz <matheuscruz.dev@gmail.com>
1 parent dcc8f61 commit cd046db

5 files changed

Lines changed: 142 additions & 5 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/test/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@
7272
<groupId>io.serverlessworkflow</groupId>
7373
<artifactId>serverlessworkflow-impl-jq</artifactId>
7474
</dependency>
75+
<dependency>
76+
<groupId>io.serverlessworkflow</groupId>
77+
<artifactId>serverlessworkflow-impl-openapi</artifactId>
78+
<version>${project.version}</version>
79+
</dependency>
7580
<dependency>
7681
<groupId>org.glassfish.jersey.media</groupId>
7782
<artifactId>jersey-media-json-jackson</artifactId>
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/CallOpenAPITaskFluent.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,24 @@ default CallOpenAPI build() {
4040

4141
SELF self();
4242

43+
/**
44+
* Sets the OpenAPI document location. This method automatically detects whether the provided
45+
* string is a literal URI or a JQ runtime expression.
46+
*
47+
* @param uri the OpenAPI document location as either a literal URI string or a JQ expression
48+
* @return this builder instance for method chaining
49+
* @see #document(URI) for setting a literal URI directly
50+
* @see #document(String, AuthenticationConfigurer) for setting a document with authentication
51+
*/
4352
default SELF document(String uri) {
44-
((CallOpenAPI) this.self().getTask())
45-
.getWith()
46-
.withDocument(
47-
new ExternalResource().withEndpoint(new Endpoint().withRuntimeExpression(uri)));
53+
if (EndpointUtil.isJqExpr(uri)) {
54+
((CallOpenAPI) this.self().getTask())
55+
.getWith()
56+
.withDocument(
57+
new ExternalResource().withEndpoint(new Endpoint().withRuntimeExpression(uri)));
58+
} else {
59+
return document(URI.create(uri));
60+
}
4861
return self();
4962
}
5063

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,8 @@ private static boolean isUrlLike(String value) {
6363
}
6464
return true;
6565
}
66+
67+
public static boolean isJqExpr(String expr) {
68+
return expr != null && expr.startsWith("${");
69+
}
6670
}

0 commit comments

Comments
 (0)