Skip to content

Commit fda2799

Browse files
committed
Work in progress
Signed-off-by: Matheus Cruz <matheuscruz.dev@gmail.com>
1 parent dc80b43 commit fda2799

9 files changed

Lines changed: 367 additions & 384 deletions

File tree

impl/openapi/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
<groupId>io.serverlessworkflow</groupId>
1717
<artifactId>serverlessworkflow-impl-core</artifactId>
1818
</dependency>
19+
<dependency>
20+
<groupId>io.serverlessworkflow</groupId>
21+
<artifactId>serverlessworkflow-api</artifactId>
22+
</dependency>
1923
<dependency>
2024
<groupId>io.serverlessworkflow</groupId>
2125
<artifactId>serverlessworkflow-impl-http</artifactId>
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
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.impl.executors.openapi;
17+
18+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
19+
import com.fasterxml.jackson.annotation.JsonProperty;
20+
import com.fasterxml.jackson.databind.JsonNode;
21+
import java.util.List;
22+
import java.util.Locale;
23+
import java.util.Map;
24+
import java.util.Optional;
25+
import java.util.Set;
26+
27+
@JsonIgnoreProperties(ignoreUnknown = true)
28+
public record MinimalOpenAPI(
29+
@JsonProperty("swagger") String swagger,
30+
List<Server> servers,
31+
String host,
32+
String basePath,
33+
List<String> schemes,
34+
Map<String, PathItem> paths,
35+
Components components,
36+
Map<String, Schema> definitions) {
37+
public MinimalOpenAPI(
38+
String swagger,
39+
List<Server> servers,
40+
String host,
41+
String basePath,
42+
List<String> schemes,
43+
Map<String, PathItem> paths,
44+
Components components,
45+
Map<String, Schema> definitions) {
46+
this.swagger = swagger;
47+
this.servers = servers;
48+
this.host = host;
49+
this.basePath = basePath;
50+
this.schemes = schemes;
51+
this.paths = paths;
52+
this.components = components;
53+
this.definitions = definitions;
54+
}
55+
56+
public enum SwaggerVersion {
57+
SWAGGER_V2,
58+
OPENAPI_V3
59+
}
60+
61+
public SwaggerVersion swaggerVersion() {
62+
return isSwaggerV2() ? SwaggerVersion.SWAGGER_V2 : SwaggerVersion.OPENAPI_V3;
63+
}
64+
65+
private boolean isSwaggerV2() {
66+
return swagger != null && swagger.trim().startsWith("2.");
67+
}
68+
69+
Optional<OperationDefinition> findOperationById(String operationId) {
70+
if (paths == null || operationId == null) {
71+
return Optional.empty();
72+
}
73+
74+
for (var entry : paths.entrySet()) {
75+
String path = entry.getKey();
76+
PathItem pathItem = entry.getValue();
77+
78+
for (var httpOperation : pathItem.methods()) {
79+
if (httpOperation.operation() != null
80+
&& operationId.equals(httpOperation.operation().operationId())) {
81+
return Optional.of(
82+
new OperationDefinition(
83+
this,
84+
httpOperation.operation(),
85+
path,
86+
httpOperation.method().toUpperCase(Locale.ROOT)));
87+
}
88+
}
89+
}
90+
return Optional.empty();
91+
}
92+
93+
public List<String> getServers() {
94+
if (swaggerVersion() == SwaggerVersion.SWAGGER_V2) {
95+
if (host == null || host.isBlank()) {
96+
return List.of();
97+
}
98+
99+
String base = host;
100+
if (basePath != null && !basePath.isBlank()) {
101+
base += basePath;
102+
}
103+
104+
return List.of(schemes.stream().findFirst().orElse("https") + "://" + base);
105+
}
106+
107+
if (servers == null || servers.isEmpty()) {
108+
return List.of();
109+
}
110+
111+
return servers.stream().map(Server::url).toList();
112+
}
113+
114+
/**
115+
* Resolves a schema reference to a Schema object.
116+
*
117+
* <p>It does not resolve nested references.
118+
*/
119+
public Schema resolveSchema(String ref) {
120+
if (isSwaggerV2()) {
121+
return resolveRefSwaggerV2(ref);
122+
} else {
123+
return resolveRefOpenAPI(ref);
124+
}
125+
}
126+
127+
private Schema resolveRefOpenAPI(String ref) {
128+
if (ref == null || !ref.startsWith("#/components/schemas/")) {
129+
return null;
130+
}
131+
132+
if (components == null || components.schemas() == null) {
133+
return null;
134+
}
135+
136+
String name = ref.substring("#/components/schemas/".length());
137+
return components.schemas().get(name);
138+
}
139+
140+
private Schema resolveRefSwaggerV2(String ref) {
141+
if (ref == null || !ref.startsWith("#/definitions/")) {
142+
return null;
143+
}
144+
145+
if (definitions == null) {
146+
return null;
147+
}
148+
149+
String name = ref.substring("#/definitions/".length());
150+
151+
return definitions.get(name);
152+
}
153+
154+
@JsonIgnoreProperties(ignoreUnknown = true)
155+
public record Server(String url) {}
156+
157+
@JsonIgnoreProperties(ignoreUnknown = true)
158+
public record PathItem(
159+
Operation get,
160+
Operation post,
161+
Operation put,
162+
Operation delete,
163+
Operation patch,
164+
Operation head,
165+
Operation options) {
166+
167+
Set<HttpOperation> methods() {
168+
return Set.of(
169+
new HttpOperation("get", get),
170+
new HttpOperation("post", post),
171+
new HttpOperation("put", put),
172+
new HttpOperation("delete", delete),
173+
new HttpOperation("patch", patch),
174+
new HttpOperation("head", head),
175+
new HttpOperation("options", options));
176+
}
177+
}
178+
179+
@JsonIgnoreProperties(ignoreUnknown = true)
180+
record HttpOperation(String method, Operation operation) {}
181+
182+
@JsonIgnoreProperties(ignoreUnknown = true)
183+
public record Operation(String operationId, List<Parameter> parameters, RequestBody requestBody) {
184+
185+
public boolean hasParameters() {
186+
return parameters != null && !parameters.isEmpty();
187+
}
188+
189+
public boolean hasRequestBody() {
190+
return requestBody != null;
191+
}
192+
}
193+
194+
@JsonIgnoreProperties(ignoreUnknown = true)
195+
public record Parameter(String name, String in, Boolean required, Schema schema) {}
196+
197+
@JsonIgnoreProperties(ignoreUnknown = true)
198+
public record RequestBody(Content content) {}
199+
200+
@JsonIgnoreProperties(ignoreUnknown = true)
201+
public record Content(@JsonProperty("application/json") MediaType applicationJson) {
202+
public boolean isApplicationJson() {
203+
return applicationJson != null;
204+
}
205+
}
206+
207+
@JsonIgnoreProperties(ignoreUnknown = true)
208+
public record MediaType(Schema schema) {}
209+
210+
@JsonIgnoreProperties(ignoreUnknown = true)
211+
public record Components(Map<String, Schema> schemas) {}
212+
213+
@JsonIgnoreProperties(ignoreUnknown = true)
214+
public record Definitions(Map<String, Schema> definitions) {}
215+
216+
@JsonIgnoreProperties(ignoreUnknown = true)
217+
public record Schema(
218+
String type,
219+
Map<String, Schema> properties,
220+
List<String> required,
221+
@JsonProperty("$ref") String ref,
222+
@JsonProperty("default") JsonNode _default) {
223+
224+
public boolean hasRef() {
225+
return ref != null && !ref.isBlank();
226+
}
227+
228+
public boolean hasProperties() {
229+
return properties != null && !properties.isEmpty();
230+
}
231+
232+
public Set<String> requiredFields() {
233+
return required == null ? Set.of() : Set.copyOf(required);
234+
}
235+
}
236+
}

0 commit comments

Comments
 (0)