Skip to content

Commit ffe2c94

Browse files
committed
fix: Fix issue with parameter on GET requests not being parsed for openapi 3.1.x
1 parent a6dc15c commit ffe2c94

4 files changed

Lines changed: 116 additions & 6 deletions

File tree

src/main/java/dev/dochia/cli/core/factory/PlaybookDataFactory.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ private Schema<?> createSyntheticSchemaForGet(List<Parameter> operationParameter
161161
if ((isPathParam || isQueryParam) && filesArguments.isNotUrlParam(parameter.getName()) && StringUtils.isNotBlank(parameter.getName())) {
162162
String newParameterName = parameter.getName() + "|" + parameter.getIn();
163163
Schema<?> originalSchema = Optional.ofNullable(parameter.getSchema()).orElse(new Schema<>());
164-
Schema<?> schemaCopy = Json.mapper().convertValue(originalSchema, Schema.class);
164+
Schema<?> schemaCopy = copySchema(originalSchema);
165165
schemaCopy.setName(newParameterName);
166166

167167
Object effectiveExample = schemaCopy.getExample() != null ? schemaCopy.getExample() : parameter.getExample();
@@ -177,6 +177,22 @@ private Schema<?> createSyntheticSchemaForGet(List<Parameter> operationParameter
177177
return syntheticSchema;
178178
}
179179

180+
/**
181+
* Creates a copy of a Schema preserving the original class type.
182+
* This is needed because {@code Json.mapper().convertValue(schema, Schema.class)} converts
183+
* OpenAPI 3.1 JsonSchema instances (which store type in {@code types} Set) into ObjectSchema,
184+
* losing the original type information.
185+
*/
186+
@SuppressWarnings("unchecked")
187+
private static Schema<?> copySchema(Schema<?> originalSchema) {
188+
Schema<?> schemaCopy = Json.mapper().convertValue(originalSchema, Schema.class);
189+
Set<String> originalTypes = originalSchema.getTypes();
190+
if (originalTypes != null && !originalTypes.isEmpty()) {
191+
schemaCopy.setTypes(new HashSet<>(originalTypes));
192+
}
193+
return schemaCopy;
194+
}
195+
180196
List<Parameter> getResolvedParameters(List<Parameter> operationParameters) {
181197
return Optional.ofNullable(operationParameters)
182198
.orElseGet(Collections::emptyList)

src/main/java/dev/dochia/cli/core/util/DochiaModelUtils.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,9 @@ public static boolean isType(Schema<?> schema, String typeToTest) {
150150
if (schema == null) {
151151
return false;
152152
}
153-
if (schema instanceof JsonSchema jsonSchema) {
154-
return Optional.ofNullable(jsonSchema.getTypes())
155-
.orElse(Set.of())
156-
.stream()
157-
.anyMatch(type -> type.equalsIgnoreCase(typeToTest));
153+
Set<String> types = schema.getTypes();
154+
if (types != null && !types.isEmpty()) {
155+
return types.stream().anyMatch(type -> type.equalsIgnoreCase(typeToTest));
158156
}
159157

160158
return typeToTest.equalsIgnoreCase(schema.getType());

src/test/java/dev/dochia/cli/core/factory/PlaybookDataFactoryTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,17 @@ void shouldGenerateApiResponsesWithSimpleSchemas() throws Exception {
734734
Assertions.assertThat(response204).isEqualTo("{}");
735735
}
736736

737+
@Test
738+
void shouldGenerateValuesForPathParamsInJsonContract() throws Exception {
739+
List<PlaybookData> dataList = setupPlaybookData("/customers/{customerId}/orders", "src/test/resources/openapi_31_params.json");
740+
Assertions.assertThat(dataList).isNotEmpty();
741+
PlaybookData getData = dataList.stream().filter(fd -> fd.getMethod() == HttpMethod.GET).findFirst().orElseThrow();
742+
String payload = getData.getPayload();
743+
Object customerId = JsonUtils.getVariableFromJson(payload, "$.customerId");
744+
Assertions.assertThat(customerId).isNotNull();
745+
Assertions.assertThat(customerId.toString()).isNotEqualTo("NOT_SET").isNotEmpty();
746+
}
747+
737748
@Test
738749
void shouldGenerateRequestWhenArrayOfArrayOfString() throws Exception {
739750
Mockito.when(processingArguments.getSelfReferenceDepth()).thenReturn(5);
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
{
2+
"openapi": "3.1.0",
3+
"info": {
4+
"title": "Custom API Project",
5+
"description": "Expose stuff",
6+
"version": "1.0.0"
7+
},
8+
"servers": [
9+
{
10+
"url": "http://localhost:8080",
11+
"description": "Generated server url"
12+
}
13+
],
14+
"tags": [
15+
{
16+
"name": "Customers",
17+
"description": "Manage customer information"
18+
}
19+
],
20+
"paths": {
21+
"/customers/{customerId}/orders": {
22+
"get": {
23+
"tags": [
24+
"Customers"
25+
],
26+
"summary": "Get orders for customer",
27+
"description": "Returns the list of orders for the specified customer.",
28+
"operationId": "getOrdersForCustomer",
29+
"parameters": [
30+
{
31+
"name": "customerId",
32+
"in": "path",
33+
"description": "An external reference for the customer",
34+
"required": true,
35+
"schema": {
36+
"type": "string",
37+
"maxLength": 64,
38+
"minLength": 3,
39+
"pattern": "[A-Za-z0-9_-]+"
40+
}
41+
},
42+
{
43+
"name": "CorrelationId",
44+
"in": "header",
45+
"description": "It allows traceability in a distributed environment",
46+
"required": true,
47+
"schema": {
48+
"type": "string",
49+
"format": "uuid"
50+
}
51+
}
52+
],
53+
"responses": {
54+
"200": {
55+
"description": "Successful response with list of orders",
56+
"content": {
57+
"application/json": {
58+
"schema": {
59+
"type": "array",
60+
"items": {
61+
"type": "string"
62+
}
63+
}
64+
}
65+
}
66+
}
67+
},
68+
"security": [
69+
{
70+
"BearerAuth": []
71+
}
72+
]
73+
}
74+
}
75+
},
76+
"components": {
77+
"securitySchemes": {
78+
"bearerAuth": {
79+
"type": "http",
80+
"scheme": "bearer",
81+
"bearerFormat": "JWT"
82+
}
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)