Skip to content

Commit 0087153

Browse files
Add builder for OpenAPIContract. (#103)
feat: add builder for OpenAPIContract. Will allow to add new fields to the contract setup without requiring to change or to add new factory methods. Co-authored-by: Pascal Krause <[email protected]>
1 parent 4ea265f commit 0087153

File tree

10 files changed

+554
-91
lines changed

10 files changed

+554
-91
lines changed

src/main/java/io/vertx/openapi/contract/OpenAPIContract.java

Lines changed: 42 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -12,134 +12,91 @@
1212

1313
package io.vertx.openapi.contract;
1414

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-
2015
import io.vertx.codegen.annotations.Nullable;
2116
import io.vertx.codegen.annotations.VertxGen;
2217
import io.vertx.core.Future;
23-
import io.vertx.core.Promise;
2418
import io.vertx.core.Vertx;
2519
import io.vertx.core.http.HttpMethod;
26-
import io.vertx.core.internal.ContextInternal;
2720
import io.vertx.core.json.JsonObject;
28-
import io.vertx.json.schema.JsonSchema;
29-
import io.vertx.json.schema.JsonSchemaValidationException;
3021
import io.vertx.json.schema.SchemaRepository;
31-
import io.vertx.openapi.contract.impl.OpenAPIContractImpl;
32-
import java.util.ArrayList;
33-
import java.util.HashMap;
3422
import java.util.List;
3523
import java.util.Map;
3624

3725
@VertxGen
3826
public interface OpenAPIContract {
3927

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+
4038
/**
4139
* Resolves / dereferences the passed contract and creates an {@link OpenAPIContract} instance.
4240
*
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.
4543
* @return A succeeded {@link Future} holding an {@link OpenAPIContract} instance, otherwise a failed {@link Future}.
4644
*/
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();
4947
}
5048

5149
/**
5250
* Resolves / dereferences the passed contract and creates an {@link OpenAPIContract} instance.
5351
*
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.
5654
* @return A succeeded {@link Future} holding an {@link OpenAPIContract} instance, otherwise a failed {@link Future}.
5755
*/
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();
6060
}
6161

6262
/**
6363
* Resolves / dereferences the passed contract and creates an {@link OpenAPIContract} instance.
6464
* <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.
6767
*
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
7171
* @return A succeeded {@link Future} holding an {@link OpenAPIContract} instance, otherwise a failed {@link Future}.
7272
*/
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) {
7575

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();
8580
}
8681

8782
/**
8883
* Resolves / dereferences the passed contract and creates an {@link OpenAPIContract} instance.
8984
* <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.
9287
*
9388
* @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
9691
* @return A succeeded {@link Future} holding an {@link OpenAPIContract} instance, otherwise a failed {@link Future}.
9792
*/
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+
143100
}
144101

145102
/**

0 commit comments

Comments
 (0)