Skip to content

Commit 41b8aeb

Browse files
authored
Merge pull request #3955 from jooby-project/3954
openapi: relax parameter validation when using openapi annotations
2 parents 433497a + 459ae6f commit 41b8aeb

4 files changed

Lines changed: 144 additions & 20 deletions

File tree

modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/OpenAPIParser.java

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,7 @@
1919
import static io.jooby.internal.openapi.AsmUtils.toMap;
2020
import static java.util.Collections.singletonList;
2121

22-
import java.util.Collections;
23-
import java.util.HashMap;
24-
import java.util.LinkedHashMap;
25-
import java.util.List;
26-
import java.util.Map;
27-
import java.util.Objects;
28-
import java.util.Optional;
22+
import java.util.*;
2923
import java.util.function.BiConsumer;
3024
import java.util.function.Consumer;
3125
import java.util.stream.Collectors;
@@ -517,24 +511,28 @@ private static void parameters(
517511
private static void parameter(
518512
ParserContext ctx, OperationExt operation, int index, Map<String, Object> parameterMap) {
519513
String name = (String) parameterMap.get("name");
520-
io.swagger.v3.oas.models.parameters.Parameter parameter;
514+
io.swagger.v3.oas.models.parameters.Parameter existingParameter;
521515
if (name != null) {
522-
parameter =
516+
existingParameter =
523517
operation.getParameters().stream()
524518
.filter(it -> it.getName().equals(name))
525519
.findFirst()
526520
.orElseGet(() -> operation.getParameter(index));
527521
} else {
528-
parameter = operation.getParameter(index);
522+
existingParameter = operation.getParameter(index);
529523
}
530-
if (parameter == null) {
531-
throw new IllegalArgumentException(
532-
"Parameter not found: "
533-
+ name
534-
+ " at position: "
535-
+ index
536-
+ " for annotation: "
537-
+ parameterMap);
524+
io.swagger.v3.oas.models.parameters.Parameter parameter;
525+
if (existingParameter == null) {
526+
// Trust user, create a new parameter;
527+
var parameterExt = new ParameterExt();
528+
arrayOrSchema(ctx, parameterMap).ifPresent(parameterExt::setSchema);
529+
parameter = parameterExt;
530+
var parameters =
531+
new ArrayList<>(Optional.ofNullable(operation.getParameters()).orElse(List.of()));
532+
parameters.add(index, parameter);
533+
operation.setParameters(parameters);
534+
} else {
535+
parameter = existingParameter;
538536
}
539537
Optional.ofNullable(name).ifPresent(parameter::setName);
540538
stringValue(parameterMap, "description", parameter::setDescription);
@@ -708,8 +706,11 @@ private static Optional<io.swagger.v3.oas.models.media.Schema> toSchema(
708706
schemaType(ctx, annotation, "anyOf", schemaMap::put);
709707
schemaType(ctx, annotation, "oneOf", schemaMap::put);
710708
schemaType(ctx, annotation, "allOf", schemaMap::put);
711-
712709
if (schemaMap.isEmpty()) {
710+
var type = (String) annotation.get("type");
711+
if (type != null) {
712+
return Optional.ofNullable(ctx.schema(type));
713+
}
713714
return Optional.empty();
714715
}
715716

modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/ParserContext.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,14 @@ public Schema schema(String type) {
426426
if (schema != null) {
427427
return schema.toSchema();
428428
}
429-
return schema(javaType(type));
429+
return switch (type) {
430+
// open-api types:
431+
case "string" -> new StringSchema();
432+
case "boolean" -> new BooleanSchema();
433+
case "number" -> new NumberSchema();
434+
case "integer" -> new IntegerSchema();
435+
default -> schema(javaType(type));
436+
};
430437
}
431438

432439
public JavaType javaType(String type) {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package issues.i3952;
7+
8+
import io.jooby.Context;
9+
import io.jooby.Jooby;
10+
import io.swagger.v3.oas.annotations.Operation;
11+
import io.swagger.v3.oas.annotations.Parameter;
12+
import io.swagger.v3.oas.annotations.enums.ParameterIn;
13+
import io.swagger.v3.oas.annotations.media.Schema;
14+
15+
public class App3952 extends Jooby {
16+
{
17+
path("/api", this::internalApiRoutes);
18+
}
19+
20+
private void internalApiRoutes() {
21+
post("/getThing", App3952::getThing);
22+
}
23+
24+
@Operation(
25+
summary = "Get a thing",
26+
parameters = {
27+
@Parameter(
28+
name = "x-api-key",
29+
description = "API Key",
30+
in = ParameterIn.HEADER,
31+
schema = @Schema(type = "string"),
32+
required = true),
33+
@Parameter(
34+
name = "x-bool",
35+
description = "Boolean key",
36+
in = ParameterIn.HEADER,
37+
schema = @Schema(type = "boolean")),
38+
@Parameter(
39+
name = "x-number",
40+
description = "Number key",
41+
in = ParameterIn.HEADER,
42+
schema = @Schema(type = "number")),
43+
@Parameter(
44+
name = "x-integer",
45+
description = "Int key",
46+
in = ParameterIn.HEADER,
47+
schema = @Schema(type = "integer"),
48+
required = true)
49+
})
50+
private static String getThing(Context context) {
51+
return "works!";
52+
}
53+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package issues.i3952;
7+
8+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
9+
10+
import io.jooby.openapi.OpenAPIResult;
11+
import io.jooby.openapi.OpenAPITest;
12+
import io.swagger.v3.oas.models.SpecVersion;
13+
14+
public class Issue3952 {
15+
@OpenAPITest(value = App3952.class, version = SpecVersion.V31)
16+
public void shouldParseNestedPath(OpenAPIResult result) {
17+
assertThat(result.toYaml())
18+
.isEqualToIgnoringNewLines(
19+
"""
20+
openapi: 3.1.0
21+
info:
22+
title: 3952 API
23+
description: 3952 API description
24+
version: "1.0"
25+
paths:
26+
/api/getThing:
27+
post:
28+
summary: Get a thing
29+
operationId: getThing
30+
parameters:
31+
- name: x-api-key
32+
in: header
33+
description: API Key
34+
required: true
35+
schema:
36+
type: string
37+
- name: x-bool
38+
in: header
39+
description: Boolean key
40+
schema:
41+
type: boolean
42+
- name: x-number
43+
in: header
44+
description: Number key
45+
schema:
46+
type: number
47+
- name: x-integer
48+
in: header
49+
description: Int key
50+
required: true
51+
schema:
52+
type: integer
53+
format: int32
54+
responses:
55+
"200":
56+
description: Success
57+
content:
58+
application/json:
59+
schema:
60+
type: string
61+
""");
62+
}
63+
}

0 commit comments

Comments
 (0)