Skip to content

Commit

Permalink
Merge pull request #445 from vert-x3/openapi_router_example
Browse files Browse the repository at this point in the history
add vertx-web-openapi-router example
  • Loading branch information
pmlopes committed Mar 24, 2023
2 parents c264d64 + 89f4128 commit 512f8f7
Show file tree
Hide file tree
Showing 4 changed files with 331 additions and 1 deletion.
7 changes: 6 additions & 1 deletion web-examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.vertx</groupId>
<artifactId>web-examples</artifactId>
<version>4.3.1</version>
<version>4.4.0</version>

<properties>
<slf4j.version>1.7.21</slf4j.version>
Expand Down Expand Up @@ -171,6 +171,11 @@
<artifactId>vertx-web-openapi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-openapi-router</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.vertx.example.web.openapi_router;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.example.util.Runner;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.openapi.router.RouterBuilder;
import io.vertx.openapi.contract.OpenAPIContract;
import io.vertx.openapi.validation.ValidatedRequest;

import java.nio.file.Path;
import java.nio.file.Paths;

import static io.vertx.ext.web.openapi.router.RouterBuilder.KEY_META_DATA_VALIDATED_REQUEST;

public class RequestValidationExample extends AbstractVerticle {

public static void main(String[] args) {
Runner.runExample(ResponseValidationExample.class);
}

private String getContractFilePath() {
Path resourceDir = Paths.get("src", "test", "resources");
Path packagePath = Paths.get(this.getClass().getPackage().getName().replace(".", "/"));
return resourceDir.resolve(packagePath).resolve("petstore.json").toString();
}

@Override
public void start(Promise<Void> startPromise) {
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 -> {
// Get the validated request
ValidatedRequest validatedRequest = routingContext.get(KEY_META_DATA_VALIDATED_REQUEST);
// Get the parameter value
int petId = validatedRequest.getPathParameters().get("petId").getInteger();

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

// 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()))
.map((Void) null)
.onComplete(startPromise);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.vertx.example.web.openapi_router;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject;
import io.vertx.example.util.Runner;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.openapi.router.OpenAPIRoute;
import io.vertx.ext.web.openapi.router.RouterBuilder;
import io.vertx.openapi.contract.OpenAPIContract;
import io.vertx.openapi.validation.ResponseValidator;
import io.vertx.openapi.validation.ValidatableResponse;

import java.nio.file.Path;
import java.nio.file.Paths;

public class ResponseValidationExample extends AbstractVerticle {

public static void main(String[] args) {
Runner.runExample(ResponseValidationExample.class);
}

private String getContractFilePath() {
Path resourceDir = Paths.get("src", "test", "resources");
Path packagePath = Paths.get(this.getClass().getPackage().getName().replace(".", "/"));
return resourceDir.resolve(packagePath).resolve("petstore.json").toString();
}

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

@Override
public void start(Promise<Void> startPromise) {
OpenAPIContract.from(vertx, getContractFilePath()).compose(contract -> {
// Create the ResponseValidator
ResponseValidator responseValidator = ResponseValidator.create(vertx, contract);
// Create the RouterBuilder
RouterBuilder routerBuilder = RouterBuilder.create(vertx, contract);
// Get the OpenAPIRoute for Operation showPetById
OpenAPIRoute showPetByIdRoute = routerBuilder.getRoute("showPetById");
// Add handler for the OpenAPIRoute
showPetByIdRoute.addHandler(routingContext -> {
// Create the payload
JsonObject pet = buildPet(1337, "Foo");
// Build the Response
ValidatableResponse validatableResponse = ValidatableResponse.create(200, pet.toBuffer(), "application/json");
// Validate the response
responseValidator.validate(validatableResponse, showPetByIdRoute.getOperation().getOperationId())
.onFailure(routingContext::fail)
// send back the validated response
.onSuccess(validatedResponse -> validatedResponse.send(routingContext.response()));
});

// 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()))
.map((Void) null)
.onComplete(startPromise);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
{
"openapi": "3.1.0",
"info": {
"version": "1.0.0",
"title": "Swagger Petstore",
"license": {
"identifier": "MIT",
"name": "MIT License"
}
},
"servers": [
{
"url": "https://petstore.swagger.io/petstore"
}
],
"security": [
{
"BasicAuth": []
}
],
"paths": {
"/pets": {
"get": {
"summary": "List all pets",
"operationId": "listPets",
"tags": [
"pets"
],
"parameters": [
{
"name": "limit",
"in": "query",
"description": "How many items to return at one time (max 100)",
"required": false,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "A paged array of pets",
"headers": {
"x-next": {
"description": "A link to the next page of responses",
"schema": {
"type": "string"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Pets"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"post": {
"summary": "Create a pet",
"operationId": "createPets",
"tags": [
"pets"
],
"requestBody": {
"description": "Pet to add to the store",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NewPet"
}
}
}
},
"responses": {
"201": {
"description": "Null response"
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/pets/{petId}": {
"get": {
"summary": "Info for a specific pet",
"operationId": "showPetById",
"tags": [
"pets"
],
"parameters": [
{
"name": "petId",
"in": "path",
"required": true,
"description": "The id of the pet to retrieve",
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "Expected response to a valid request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Pet"
}
}
}
},
"404": {
"description": "Pet not found"
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Pet": {
"allOf": [
{
"$ref": "#/components/schemas/NewPet"
},
{
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
}
}
}
]
},
"NewPet": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
},
"Pets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Pet"
}
},
"Error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
}
}
}
}
}

0 comments on commit 512f8f7

Please sign in to comment.