|
12 | 12 |
|
13 | 13 | package io.vertx.openapi.contract; |
14 | 14 |
|
15 | | -import static io.vertx.core.Future.failedFuture; |
16 | | -import static io.vertx.openapi.contract.OpenAPIContractException.createInvalidContract; |
17 | | -import static io.vertx.openapi.impl.Utils.readYamlOrJson; |
18 | | -import static java.util.Collections.emptyMap; |
19 | | - |
20 | 15 | import io.vertx.codegen.annotations.Nullable; |
21 | 16 | import io.vertx.codegen.annotations.VertxGen; |
22 | 17 | import io.vertx.core.Future; |
23 | | -import io.vertx.core.Promise; |
24 | 18 | import io.vertx.core.Vertx; |
25 | 19 | import io.vertx.core.http.HttpMethod; |
26 | | -import io.vertx.core.internal.ContextInternal; |
27 | 20 | import io.vertx.core.json.JsonObject; |
28 | | -import io.vertx.json.schema.JsonSchema; |
29 | | -import io.vertx.json.schema.JsonSchemaValidationException; |
30 | 21 | import io.vertx.json.schema.SchemaRepository; |
31 | | -import io.vertx.openapi.contract.impl.OpenAPIContractImpl; |
32 | | -import java.util.ArrayList; |
33 | | -import java.util.HashMap; |
34 | 22 | import java.util.List; |
35 | 23 | import java.util.Map; |
36 | 24 |
|
37 | 25 | @VertxGen |
38 | 26 | public interface OpenAPIContract { |
39 | 27 |
|
| 28 | + /** |
| 29 | + * Instantiates a new builder for an openapi-contract. |
| 30 | + * |
| 31 | + * @param vertx The vert.x instance |
| 32 | + * @return A new builder. |
| 33 | + */ |
| 34 | + static OpenAPIContractBuilder builder(Vertx vertx) { |
| 35 | + return new OpenAPIContractBuilder(vertx); |
| 36 | + } |
| 37 | + |
40 | 38 | /** |
41 | 39 | * Resolves / dereferences the passed contract and creates an {@link OpenAPIContract} instance. |
42 | 40 | * |
43 | | - * @param vertx The related Vert.x instance. |
44 | | - * @param unresolvedContractPath The path to the unresolved contract. |
| 41 | + * @param vertx The related Vert.x instance. |
| 42 | + * @param contractPath The path to the contract. |
45 | 43 | * @return A succeeded {@link Future} holding an {@link OpenAPIContract} instance, otherwise a failed {@link Future}. |
46 | 44 | */ |
47 | | - static Future<OpenAPIContract> from(Vertx vertx, String unresolvedContractPath) { |
48 | | - return readYamlOrJson(vertx, unresolvedContractPath).compose(json -> from(vertx, json)); |
| 45 | + static Future<OpenAPIContract> from(Vertx vertx, String contractPath) { |
| 46 | + return builder(vertx).setContractPath(contractPath).build(); |
49 | 47 | } |
50 | 48 |
|
51 | 49 | /** |
52 | 50 | * Resolves / dereferences the passed contract and creates an {@link OpenAPIContract} instance. |
53 | 51 | * |
54 | | - * @param vertx The related Vert.x instance. |
55 | | - * @param unresolvedContract The unresolved contract. |
| 52 | + * @param vertx The related Vert.x instance. |
| 53 | + * @param contract The contract. |
56 | 54 | * @return A succeeded {@link Future} holding an {@link OpenAPIContract} instance, otherwise a failed {@link Future}. |
57 | 55 | */ |
58 | | - static Future<OpenAPIContract> from(Vertx vertx, JsonObject unresolvedContract) { |
59 | | - return from(vertx, unresolvedContract, emptyMap()); |
| 56 | + static Future<OpenAPIContract> from(Vertx vertx, JsonObject contract) { |
| 57 | + return builder(vertx) |
| 58 | + .setContract(contract) |
| 59 | + .build(); |
60 | 60 | } |
61 | 61 |
|
62 | 62 | /** |
63 | 63 | * Resolves / dereferences the passed contract and creates an {@link OpenAPIContract} instance. |
64 | 64 | * <p> |
65 | | - * This method can be used in case that the contract is split into several files. These files can be passed in a |
66 | | - * Map that has the reference as key and the path to the file as value. |
| 65 | + * This method can be used in case that the contract is split into several parts. These parts can be passed in a |
| 66 | + * Map that has the reference as key and the path to the part as value. |
67 | 67 | * |
68 | | - * @param vertx The related Vert.x instance. |
69 | | - * @param unresolvedContractPath The path to the unresolved contract. |
70 | | - * @param additionalContractFiles The additional contract files |
| 68 | + * @param vertx The related Vert.x instance. |
| 69 | + * @param contractPath The path to the contract. |
| 70 | + * @param additionalContractPartPaths The additional contract part paths |
71 | 71 | * @return A succeeded {@link Future} holding an {@link OpenAPIContract} instance, otherwise a failed {@link Future}. |
72 | 72 | */ |
73 | | - static Future<OpenAPIContract> from(Vertx vertx, String unresolvedContractPath, |
74 | | - Map<String, String> additionalContractFiles) { |
| 73 | + static Future<OpenAPIContract> from(Vertx vertx, String contractPath, |
| 74 | + Map<String, String> additionalContractPartPaths) { |
75 | 75 |
|
76 | | - Map<String, Future<JsonObject>> jsonFilesFuture = new HashMap<>(); |
77 | | - jsonFilesFuture.put(unresolvedContractPath, readYamlOrJson(vertx, unresolvedContractPath)); |
78 | | - additionalContractFiles.forEach((key, value) -> jsonFilesFuture.put(key, readYamlOrJson(vertx, value))); |
79 | | - |
80 | | - return Future.all(new ArrayList<>(jsonFilesFuture.values())).compose(compFut -> { |
81 | | - Map<String, JsonObject> resolvedFiles = new HashMap<>(); |
82 | | - additionalContractFiles.keySet().forEach(key -> resolvedFiles.put(key, jsonFilesFuture.get(key).result())); |
83 | | - return from(vertx, jsonFilesFuture.get(unresolvedContractPath).result(), resolvedFiles); |
84 | | - }); |
| 76 | + return builder(vertx) |
| 77 | + .setContractPath(contractPath) |
| 78 | + .setAdditionalContractPartPaths(additionalContractPartPaths) |
| 79 | + .build(); |
85 | 80 | } |
86 | 81 |
|
87 | 82 | /** |
88 | 83 | * Resolves / dereferences the passed contract and creates an {@link OpenAPIContract} instance. |
89 | 84 | * <p> |
90 | | - * This method can be used in case that the contract is split into several files. These files can be passed in a |
91 | | - * Map that has the reference as key and the path to the file as value. |
| 85 | + * This method can be used in case that the contract is split into several parts. These parts can be passed in a |
| 86 | + * Map that has the reference as key and the part as value. |
92 | 87 | * |
93 | 88 | * @param vertx The related Vert.x instance. |
94 | | - * @param unresolvedContract The unresolved contract. |
95 | | - * @param additionalContractFiles The additional contract files |
| 89 | + * @param contract The unresolved contract. |
| 90 | + * @param additionalContractParts The additional contract parts |
96 | 91 | * @return A succeeded {@link Future} holding an {@link OpenAPIContract} instance, otherwise a failed {@link Future}. |
97 | 92 | */ |
98 | | - static Future<OpenAPIContract> from(Vertx vertx, JsonObject unresolvedContract, |
99 | | - Map<String, JsonObject> additionalContractFiles) { |
100 | | - if (unresolvedContract == null) { |
101 | | - return failedFuture(createInvalidContract("Spec must not be null")); |
102 | | - } |
103 | | - |
104 | | - OpenAPIVersion version = OpenAPIVersion.fromContract(unresolvedContract); |
105 | | - String baseUri = "app://"; |
106 | | - |
107 | | - ContextInternal ctx = (ContextInternal) vertx.getOrCreateContext(); |
108 | | - Promise<OpenAPIContract> promise = ctx.promise(); |
109 | | - |
110 | | - version.getRepository(vertx, baseUri) |
111 | | - .compose(repository -> { |
112 | | - List<Future<?>> validationFutures = new ArrayList<>(additionalContractFiles.size()); |
113 | | - for (String ref : additionalContractFiles.keySet()) { |
114 | | - // Todo: As soon a more modern Java version is used the validate part could be extracted in a private static |
115 | | - // method and reused below. |
116 | | - JsonObject file = additionalContractFiles.get(ref); |
117 | | - Future<?> validationFuture = version.validateAdditionalContractFile(vertx, repository, file) |
118 | | - .compose(v -> vertx.executeBlocking(() -> repository.dereference(ref, JsonSchema.of(ref, file)))); |
119 | | - |
120 | | - validationFutures.add(validationFuture); |
121 | | - } |
122 | | - return Future.all(validationFutures).map(repository); |
123 | | - }).compose(repository -> version.validateContract(vertx, repository, unresolvedContract).compose(res -> { |
124 | | - try { |
125 | | - res.checkValidity(); |
126 | | - return version.resolve(vertx, repository, unresolvedContract); |
127 | | - } catch (JsonSchemaValidationException | UnsupportedOperationException e) { |
128 | | - return failedFuture(createInvalidContract(null, e)); |
129 | | - } |
130 | | - }) |
131 | | - .map(resolvedSpec -> (OpenAPIContract) new OpenAPIContractImpl(resolvedSpec, version, repository))) |
132 | | - .recover(e -> { |
133 | | - // Convert any non-openapi exceptions into an OpenAPIContractException |
134 | | - if (e instanceof OpenAPIContractException) { |
135 | | - return failedFuture(e); |
136 | | - } |
137 | | - |
138 | | - return failedFuture( |
139 | | - createInvalidContract("Found issue in specification for reference: " + e.getMessage(), e)); |
140 | | - }).onComplete(promise); |
141 | | - |
142 | | - return promise.future(); |
| 93 | + static Future<OpenAPIContract> from(Vertx vertx, JsonObject contract, |
| 94 | + Map<String, JsonObject> additionalContractParts) { |
| 95 | + return builder(vertx) |
| 96 | + .setContract(contract) |
| 97 | + .setAdditionalContractParts(additionalContractParts) |
| 98 | + .build(); |
| 99 | + |
143 | 100 | } |
144 | 101 |
|
145 | 102 | /** |
|
0 commit comments