Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ public void add(FilterBy aFilterBy) {
filterBys.add(aFilterBy);
}

public void addAll(final QueryFilterParams params) {
if (params == null) {
return;
}

for (FilterBy filterBy : params.toList()) {
add(new FilterBy(filterBy.fieldName, filterBy.filterOperation + filterBy.fieldValue));
}
}

public FilterBy get(int i) {
return filterBys.get(i);
}
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<thingifier.version>1.5.6-SNAPSHOT</thingifier.version>
<swagger-models-version>2.2.27</swagger-models-version>
<swagger-models-version>2.2.52</swagger-models-version>
<gson-version>2.8.6</gson-version>
<sqlite-jdbc-version>3.53.2.0</sqlite-jdbc-version>
<snakeyaml-version>2.6</snakeyaml-version>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package uk.co.compendiumdev.thingifier.swaggerizer;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import uk.co.compendiumdev.thingifier.Thingifier;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingDefinition;
Expand All @@ -26,6 +29,53 @@ public void canCreateSwagger() {
apiDefn.addServer("http://localhost:4567", "local execution");
apiDefn.setVersion("1.0.1");

System.out.println(new Swaggerizer(apiDefn).asJson());
String swagger = new Swaggerizer(apiDefn).asJson();

Assertions.assertTrue(openApiVersion(swagger).startsWith("3.1."));
Assertions.assertTrue(swagger.contains("\"x-query-operation\""));
Assertions.assertTrue(swagger.contains("application/x-www-form-urlencoded"));
}

@Test
public void canCreateOpenApi30Swagger() {
Thingifier t = new TodoListThingifierTestModel().get();

ThingifierApiDocumentationDefn apiDefn = new ThingifierApiDocumentationDefn();
apiDefn.setThingifier(t);
apiDefn.setVersion("1.0.1");

String swagger = new Swaggerizer(apiDefn).asJson(OpenApiSpecificationVersion.OPENAPI_3_0);

Assertions.assertTrue(openApiVersion(swagger).startsWith("3.0."));
Assertions.assertTrue(swagger.contains("\"x-query-operation\""));
Assertions.assertTrue(swagger.contains("application/x-www-form-urlencoded"));
}

@Test
public void canCreateOpenApi32Swagger() {
Thingifier t = new TodoListThingifierTestModel().get();

ThingifierApiDocumentationDefn apiDefn = new ThingifierApiDocumentationDefn();
apiDefn.setThingifier(t);
apiDefn.setVersion("1.0.1");

String swagger = new Swaggerizer(apiDefn).asJson(OpenApiSpecificationVersion.OPENAPI_3_2);
JsonObject document = JsonParser.parseString(swagger).getAsJsonObject();
JsonObject todos = document.getAsJsonObject("paths").getAsJsonObject("/todos");
JsonObject query = todos.getAsJsonObject("query");

Assertions.assertEquals("3.2.0", openApiVersion(swagger));
Assertions.assertTrue(todos.has("query"));
Assertions.assertFalse(swagger.contains("\"x-query-operation\""));
Assertions.assertFalse(swagger.contains("\"x-http-method\""));
Assertions.assertFalse(swagger.contains("\"x-query-content-types\""));
Assertions.assertTrue(
query.getAsJsonObject("requestBody")
.getAsJsonObject("content")
.has("application/x-www-form-urlencoded"));
}

private String openApiVersion(final String swagger) {
return JsonParser.parseString(swagger).getAsJsonObject().get("openapi").getAsString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ private void appendHeader(final StringBuilder html) {
html.append(" <a href=\"/swagger\">Swagger UI</a>\n");
html.append(" <a href=\"/docs/swagger\">Download OpenAPI</a>\n");
html.append(" <a href=\"/openapi.json\">Raw OpenAPI JSON</a>\n");
html.append(" <a href=\"/openapi-3.1.json\">OpenAPI 3.1 JSON</a>\n");
html.append(" <a href=\"/openapi-3.2.json\">OpenAPI 3.2 JSON</a>\n");
html.append(" <a href=\"/openapi-3.0.json\">OpenAPI 3.0 JSON</a>\n");
html.append(" </nav>\n");
html.append(" <h1>").append(escape(title())).append(" API Documentation</h1>\n");
if (!description().isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.LinkedHashMap;
import java.util.Map;
import uk.co.compendiumdev.thingifier.swaggerizer.OpenApiSpecificationVersion;
import uk.co.compendiumdev.thingifier.yaml.ThingifierYamlException;

public final class CrudUiController {
Expand Down Expand Up @@ -188,6 +189,11 @@ public UiHttpResponse openApiJson() {
200, new OpenApiDocumentation(workspace.snapshot()).openApiJson());
}

public UiHttpResponse openApiJson(final OpenApiSpecificationVersion version) {
return UiHttpResponse.json(
200, new OpenApiDocumentation(workspace.snapshot()).openApiJson(version));
}

public UiHttpResponse downloadOpenApi(final boolean permissive) {
OpenApiDocumentation openApi = new OpenApiDocumentation(workspace.snapshot());
Map<String, String> headers = new LinkedHashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Locale;
import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn;
import uk.co.compendiumdev.thingifier.swaggerizer.OpenApiSpecificationVersion;
import uk.co.compendiumdev.thingifier.swaggerizer.Swaggerizer;

public final class OpenApiDocumentation {
Expand All @@ -15,11 +16,16 @@ public OpenApiDocumentation(final WorkspaceSnapshot snapshot) {
}

public String openApiJson() {
return new Swaggerizer(apiDefinition()).asJson();
return openApiJson(OpenApiSpecificationVersion.OPENAPI_3_1);
}

public String openApiJson(final OpenApiSpecificationVersion version) {
return new Swaggerizer(apiDefinition()).asJson(version);
}

public String permissiveOpenApiJson() {
return new Swaggerizer(apiDefinition()).asJson(true);
return new Swaggerizer(apiDefinition())
.asJson(OpenApiSpecificationVersion.OPENAPI_3_1, true);
}

public String downloadFilename(final boolean permissive) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ public String html() {
+ "<script>\n"
+ "window.onload = function () {\n"
+ " window.ui = SwaggerUIBundle({\n"
+ " url: \"/openapi.json\",\n"
+ " urls: [\n"
+ " { url: \"/openapi.json\", name: \"OpenAPI 3.1 default\" },\n"
+ " { url: \"/openapi-3.1.json\", name: \"OpenAPI 3.1\" },\n"
+ " { url: \"/openapi-3.2.json\", name: \"OpenAPI 3.2\" },\n"
+ " { url: \"/openapi-3.0.json\", name: \"OpenAPI 3.0\" }\n"
+ " ],\n"
+ " \"urls.primaryName\": \"OpenAPI 3.1 default\",\n"
+ " dom_id: \"#swagger-ui\",\n"
+ " deepLinking: true,\n"
+ " presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],\n"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import uk.co.compendiumdev.thingifier.crudui.DynamicThingifierApiProxy;
import uk.co.compendiumdev.thingifier.crudui.ResourceReader;
import uk.co.compendiumdev.thingifier.crudui.UiHttpResponse;
import uk.co.compendiumdev.thingifier.swaggerizer.OpenApiSpecificationVersion;

public final class CrudUiApplication implements AutoCloseable {

Expand Down Expand Up @@ -100,6 +101,24 @@ public void configureRoutes() {
request.queryParam("permissive") != null)));
ServerRoutes.get(
"/openapi.json", (request, response) -> write(response, controller.openApiJson()));
ServerRoutes.get(
"/openapi-3.1.json",
(request, response) ->
write(
response,
controller.openApiJson(OpenApiSpecificationVersion.OPENAPI_3_1)));
ServerRoutes.get(
"/openapi-3.2.json",
(request, response) ->
write(
response,
controller.openApiJson(OpenApiSpecificationVersion.OPENAPI_3_2)));
ServerRoutes.get(
"/openapi-3.0.json",
(request, response) ->
write(
response,
controller.openApiJson(OpenApiSpecificationVersion.OPENAPI_3_0)));
ServerRoutes.get(
"/swagger", (request, response) -> write(response, controller.swaggerUi()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import uk.co.compendiumdev.thingifier.swaggerizer.OpenApiSpecificationVersion;

public class CrudUiControllerTest {

Expand Down Expand Up @@ -296,12 +297,51 @@ public void openApiJsonUsesActiveWorkspaceApiServer() {
Assertions.assertEquals(200, response.statusCode());
Assertions.assertEquals("application/json", response.contentType());
Assertions.assertTrue(response.body().contains("\"openapi\""));
Assertions.assertTrue(openApiVersion(response.body()).startsWith("3.1."));
Assertions.assertTrue(response.body().contains("\"/api\""));
Assertions.assertTrue(response.body().contains("\"/projects\""));
Assertions.assertTrue(response.body().contains("\"/projects/{id}/tasks\""));
}
}

@Test
public void openApiJsonCanBeGeneratedForOpenApi30() {
try (ActiveThingifierWorkspace workspace =
ActiveThingifierWorkspace.defaultTodoManagerWorkspace()) {
workspace.replaceWithYaml(TestResources.text("/models/project-tasks.yaml"));
CrudUiController controller = new CrudUiController(workspace);

UiHttpResponse response =
controller.openApiJson(OpenApiSpecificationVersion.OPENAPI_3_0);

Assertions.assertEquals(200, response.statusCode());
Assertions.assertEquals("application/json", response.contentType());
Assertions.assertTrue(openApiVersion(response.body()).startsWith("3.0."));
Assertions.assertTrue(response.body().contains("\"/api\""));
Assertions.assertTrue(response.body().contains("\"/projects/{id}/tasks\""));
}
}

@Test
public void openApiJsonCanBeGeneratedForOpenApi32() {
try (ActiveThingifierWorkspace workspace =
ActiveThingifierWorkspace.defaultTodoManagerWorkspace()) {
workspace.replaceWithYaml(TestResources.text("/models/project-tasks.yaml"));
CrudUiController controller = new CrudUiController(workspace);

UiHttpResponse response =
controller.openApiJson(OpenApiSpecificationVersion.OPENAPI_3_2);

Assertions.assertEquals(200, response.statusCode());
Assertions.assertEquals("application/json", response.contentType());
Assertions.assertEquals("3.2.0", openApiVersion(response.body()));
Assertions.assertTrue(response.body().contains("\"/api\""));
Assertions.assertTrue(response.body().contains("\"/projects/{id}/tasks\""));
Assertions.assertTrue(response.body().contains("\"query\""));
Assertions.assertFalse(response.body().contains("\"x-query-operation\""));
}
}

@Test
public void openApiDownloadAddsAttachmentHeader() {
try (ActiveThingifierWorkspace workspace =
Expand Down Expand Up @@ -356,10 +396,14 @@ public void swaggerUiPageEmbedsUnpkgSwaggerUiForCurrentOpenApiJson() {
Assertions.assertTrue(response.body().contains("href=\"/favicon.svg\""));
Assertions.assertTrue(response.body().contains("SwaggerUIBundle"));
Assertions.assertTrue(response.body().contains("/openapi.json"));
Assertions.assertTrue(response.body().contains("/openapi-3.1.json"));
Assertions.assertTrue(response.body().contains("/openapi-3.2.json"));
Assertions.assertTrue(response.body().contains("/openapi-3.0.json"));
Assertions.assertTrue(response.body().contains("/css/swagger-copy-for-ai.css"));
Assertions.assertTrue(response.body().contains("/js/swagger-copy-for-ai.js"));
Assertions.assertTrue(response.body().contains("window.thingifierSwaggerCopyForAi"));
Assertions.assertTrue(response.body().contains("openApiUrl: \"/openapi.json\""));
Assertions.assertTrue(response.body().contains("\"urls.primaryName\""));
}
}

Expand Down Expand Up @@ -484,4 +528,8 @@ public void faviconResourceIsAvailableAndSimple() {
Assertions.assertTrue(favicon.contains("#f1c84c"));
Assertions.assertFalse(favicon.contains("<text"));
}

private String openApiVersion(final String openApiJson) {
return JsonParser.parseString(openApiJson).getAsJsonObject().get("openapi").getAsString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ public void staticPagesAndGeneratedDocumentationAreReachable() {
assertStatusContains("/swagger", 200, "SwaggerUIBundle");
assertStatusContains("/swagger", 200, "swagger-copy-for-ai.js");
assertStatusContains("/openapi.json", 200, "\"openapi\"");
assertStatusContains("/openapi-3.1.json", 200, "\"openapi\"");
assertStatusContains("/openapi-3.2.json", 200, "\"openapi\"");
assertStatusContains("/openapi-3.0.json", 200, "\"openapi\"");
assertStatusContains("/docs/swagger", 200, "\"openapi\"");

CrudUiApiClient.ApiResult removedAlias = api.get("/openapi-3-1.json");
Assertions.assertEquals(404, removedAlias.statusCode(), removedAlias.body());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
public enum HttpRouteVerb {
GET,
HEAD,
QUERY,
OPTIONS,
POST,
PUT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public static void head(final String path, final HttpRouteHandler handler) {
route(HttpRouteVerb.HEAD, path, handler);
}

public static void query(final String path, final HttpRouteHandler handler) {
route(HttpRouteVerb.QUERY, path, handler);
}

public static void options(final String path, final HttpRouteHandler handler) {
route(HttpRouteVerb.OPTIONS, path, handler);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ public static void addHandler(
case "head":
head(endpoint, route);
break;
case "query":
query(endpoint, route);
break;
case "options":
options(endpoint, route);
break;
Expand Down Expand Up @@ -121,7 +124,9 @@ public static void addHandler(
public static void routeStatusWhenNot(
final int statuscode, final String endpoint, final List<String> excludedVerbs) {

String[] verbs = {"get", "options", "head", "put", "post", "patch", "trace", "delete"};
String[] verbs = {
"get", "options", "head", "query", "put", "post", "patch", "trace", "delete"
};

for (String verb : verbs) {
if (!excludedVerbs.contains(verb)) {
Expand Down
Loading
Loading