Skip to content

Commit

Permalink
fix: OpenAPI examples (#464)
Browse files Browse the repository at this point in the history
  • Loading branch information
pk-work authored Nov 15, 2024
1 parent 843d13f commit 8454a25
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 249 deletions.
6 changes: 3 additions & 3 deletions openapi-examples/README.adoc
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
= Vert.x JUnit 5 examples
= Vert.x OpenAPIs examples

This project illustrates how to use https://vertx.io/docs/vertx-openapi/java/[Vert.x OpenAPI] for validating incoming requests.

The link:src/test/java/io/vertx/example/openapi/CreateContract.java[CreateContract.java] file contains examples to explain how an OpenAPIContract class can be instantiated.
The link:src/main/java/io/vertx/example/openapi/CreateContract.java[CreateContract.java] file contains examples to explain how an OpenAPIContract class can be instantiated.

The link:src/test/java/io/vertx/example/openapi/ValidateRequest.java[ValidateRequest.java] file contains examples to explain how an incoming request can be validated against an OpenAPIContract.
The link:src/main/java/io/vertx/example/openapi/ValidateRequest.java[ValidateRequest.java] file contains examples to explain how an incoming request can be validated against an OpenAPIContract.

It is highly recommended to also check the https://vertx.io/docs/vertx-web-openapi-router/java/[Vert.x OpenAPI Router], in case you haven't heard about it yet.
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,41 @@
package io.vertx.example.openapi;

import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient;
import io.vertx.openapi.validation.RequestValidator;

public class ValidateRequest {

public static void main(String[] args) {
Vertx vertx = Vertx.vertx();

CreateContract.createContract(vertx).map(openAPIContract -> RequestValidator.create(vertx, openAPIContract))
.onSuccess(requestValidator -> {
CreateContract.createContract(vertx).map(openAPIContract -> {
// creates the RequestValidator
return RequestValidator.create(vertx, openAPIContract);
}).onSuccess(requestValidator -> {
System.out.println("RequestValidator created");
vertx.createHttpServer().requestHandler(req ->
// validate the request
requestValidator.validate(req).onFailure(t -> {
System.out.println("Request is invalid: " + t.getMessage());
req.response().setStatusCode(400).end(t.getMessage());
}).onSuccess(validatedRequest -> System.out.println("Request is valid"))
).listen(8080, "localhost");
System.out.println("HttpServer created");
}).onSuccess(validatedRequest -> {
System.out.println("Request is valid");
req.response().setStatusCode(200).end();
})
).listen(8080, "localhost").onSuccess(server -> {
System.out.println("HttpServer started on port " + server.actualPort());

WebClient.create(vertx)
.post(server.actualPort(), "localhost", "/v1/pets")
// send post request with a payload that does not fit to the contract
.sendJson(new JsonObject())
.onSuccess(response -> {
System.out.println("Response status code expected 400: " + response.statusCode());
System.exit(0);
});
});
}).onFailure(t -> {
t.printStackTrace();
System.exit(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import io.vertx.core.Future;
import io.vertx.core.VerticleBase;
import io.vertx.core.http.HttpServer;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.openapi.router.RouterBuilder;
import io.vertx.launcher.application.VertxApplication;
import io.vertx.openapi.contract.OpenAPIContract;
Expand All @@ -16,38 +19,92 @@
public class RequestValidationExample extends VerticleBase {

public static void main(String[] args) {
VertxApplication.main(new String[]{ResponseValidationExample.class.getName()});
VertxApplication.main(new String[]{RequestValidationExample.class.getName()});
}

private String getContractFilePath() {
Path resourceDir = Paths.get("src", "test", "resources");
Path resourceDir = Paths.get("src", "main", "resources");
Path packagePath = Paths.get(this.getClass().getPackage().getName().replace(".", "/"));
return resourceDir.resolve(packagePath).resolve("petstore.json").toString();
Path filePath = resourceDir.resolve(packagePath).resolve("petstore.yaml");
if (filePath.toAbsolutePath().toString().contains("web-examples")) {
return filePath.toString();
} else {
return Path.of("web-examples").resolve(filePath).toString();
}
}


private JsonObject buildPet(int id, String name) {
return new JsonObject().put("id", id).put("name", name);
}


@Override
public Future<?> start() {
return OpenAPIContract
JsonObject expectedPet = buildPet(1337, "Foo");

Future<HttpServer> serverStarted = OpenAPIContract
.from(vertx, getContractFilePath())
.compose(contract -> {
// Create the RouterBuilder
RouterBuilder routerBuilder = RouterBuilder.create(vertx, contract);
// Add handler for Operation showPetById
routerBuilder.getRoute("showPetById").addHandler(routingContext -> {
routerBuilder.getRoute("createPets").addHandler(routingContext -> {
// Get the validated request
ValidatedRequest validatedRequest = routingContext.get(KEY_META_DATA_VALIDATED_REQUEST);
// Get the parameter value
int petId = validatedRequest.getPathParameters().get("petId").getInteger();
JsonObject newPet = validatedRequest.getBody().getJsonObject();
if (newPet.equals(expectedPet)) {
System.out.println("Request is valid");
}

routingContext.response().setStatusCode(201).end();
});

Router basePathRouter = Router.router(vertx);
// Create the OpenAPi Router and mount it on the base path (must match the contract)
basePathRouter.route("/v1/*").subRouter(routerBuilder.createRouter());

return vertx.createHttpServer().requestHandler(basePathRouter).listen(0, "localhost");
}).onSuccess(server -> {
System.out.println("Server started on port " + server.actualPort());
}).onFailure(t -> {
t.printStackTrace();
System.exit(1);
});

/**
* Send a request that does fit to the contract
*/
serverStarted.onSuccess(server -> {
WebClient.create(vertx)
.post(server.actualPort(), "localhost", "/v1/pets")
// send post request with a payload that does fit to the contract
.sendJson(expectedPet)
.onSuccess(response -> {
System.out.println("Response status code expected 201: " + response.statusCode());
}).onFailure(t -> {
t.printStackTrace();
System.exit(1);
});
});

// Due to the fact that we don't validate the resonse here, you can send back a response,
// that doesn't fit to the contract
routingContext.response().setStatusCode(200).end();
/**
* Send a request that does not fit to the contract
*/
serverStarted.onSuccess(server -> {
WebClient.create(vertx)
.post(server.actualPort(), "localhost", "/v1/pets")
// send post request with a payload that does not fit to the contract
.sendJson(new JsonObject())
.onSuccess(response -> {
System.out.println("Response status code expected 400: " + response.statusCode());
}).onFailure(t -> {
t.printStackTrace();
System.exit(1);
});
});

// Create the Router
Router router = routerBuilder.createRouter();
return vertx.createHttpServer().requestHandler(router).listen(0, "localhost");
})
.onSuccess(server -> System.out.println("Server started on port " + server.actualPort()));
return serverStarted;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.vertx.core.VerticleBase;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.openapi.router.OpenAPIRoute;
import io.vertx.ext.web.openapi.router.RouterBuilder;
import io.vertx.launcher.application.VertxApplication;
Expand All @@ -21,9 +22,14 @@ public static void main(String[] args) {
}

private String getContractFilePath() {
Path resourceDir = Paths.get("src", "test", "resources");
Path resourceDir = Paths.get("src", "main", "resources");
Path packagePath = Paths.get(this.getClass().getPackage().getName().replace(".", "/"));
return resourceDir.resolve(packagePath).resolve("petstore.json").toString();
Path filePath = resourceDir.resolve(packagePath).resolve("petstore.yaml");
if (filePath.toAbsolutePath().toString().contains("web-examples")) {
return filePath.toString();
} else {
return Path.of("web-examples").resolve(filePath).toString();
}
}

private JsonObject buildPet(int id, String name) {
Expand Down Expand Up @@ -55,9 +61,24 @@ public Future<?> start() {
});

// Create the Router
Router router = routerBuilder.createRouter();
return vertx.createHttpServer().requestHandler(router).listen(0, "localhost");
})
.onSuccess(server -> System.out.println("Server started on port " + server.actualPort()));
Router basePathRouter = Router.router(vertx);
// Create the OpenAPi Router and mount it on the base path (must match the contract)
basePathRouter.route("/v1/*").subRouter(routerBuilder.createRouter());

return vertx.createHttpServer().requestHandler(basePathRouter).listen(0, "localhost");
}).onSuccess(server -> {
System.out.println("Server started on port " + server.actualPort());

WebClient.create(vertx)
.get(server.actualPort(), "localhost", "/v1/pets/1337")
// send request with a payload that does fit to the contract
.send().onSuccess(response -> {
System.out.println("Response status code expected 200: " + response.statusCode());
System.exit(0);
}).onFailure(t -> {
t.printStackTrace();
System.exit(1);
});
});
}
}
Loading

0 comments on commit 8454a25

Please sign in to comment.