Skip to content

Commit

Permalink
Resolved vitrivr#160 by properly documenting and refactoring APIEndpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
sauterl committed Dec 4, 2020
1 parent 4a471d1 commit 4e2ed9a
Show file tree
Hide file tree
Showing 13 changed files with 614 additions and 423 deletions.
414 changes: 209 additions & 205 deletions cineast-api/src/main/java/org/vitrivr/cineast/api/APIEndpoint.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

import java.io.IOException;
import org.vitrivr.cineast.api.APIEndpoint;
import org.vitrivr.cineast.standalone.cli.CineastCli;
import org.vitrivr.cineast.api.rest.OpenApiCompatHelper;
import org.vitrivr.cineast.standalone.config.Config;
import org.vitrivr.cineast.standalone.util.CLI;

/**
* Main class for standalone persistent openapi specs generation.
Expand Down Expand Up @@ -32,7 +31,7 @@ public static void main(String[] args) {
}

try {
APIEndpoint.getInstance().writeOpenApiDocPersistently("docs/openapi.json"); // TODO use config?
OpenApiCompatHelper.writeOpenApiDocPersistently(APIEndpoint.getInstance(), "docs/openapi.json"); // TODO use config?
} catch (IOException e) {
e.printStackTrace();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package org.vitrivr.cineast.api.rest;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.javalin.plugin.openapi.OpenApiOptions;
import io.javalin.plugin.openapi.ui.ReDocOptions;
import io.javalin.plugin.openapi.ui.SwaggerOptions;
import io.swagger.v3.core.jackson.ModelResolver;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.tags.Tag;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.vitrivr.cineast.api.APIEndpoint;
import org.vitrivr.cineast.standalone.config.APIConfig;

import java.util.Arrays;
import java.util.List;

/**
* Helper class for openapi compatibility.
*
* @author Loris Sauter
* @version 1.0
*/
public class OpenApiCompatHelper {

/**
* OpenAPI Specification tag for metadata related routes
*/
public static final String METADATA_OAS_TAG = "Metadata";
public static final String SEGMENT_OAS_TAG = "Segment";


public static final List<Tag> OAS_TAGS = Arrays.asList(
new Tag().name(METADATA_OAS_TAG).description("Metadata related operations")
);
private static final Logger LOGGER = LogManager.getLogger();

private OpenApiCompatHelper() {
/* A static helper class. */
}

/**
* Creates the Javalin options used to create an OpenAPI specification.
*
* @param config
* @return
*/
public static OpenApiOptions getJavalinOpenApiOptions(APIConfig config) {
//Default Javalin JSON mapper includes all null values and breaks spec json
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

return new OpenApiOptions(() -> getOpenApi(config))
.path("/openapi-specs")
.activateAnnotationScanningFor("org.vitrivr.cineast.api")
// .toJsonMapper(new JacksonToJsonMapper())
// .modelConverterFactory(new JacksonModelConverterFactory())
.toJsonMapper(o -> {
try {
return mapper.writeValueAsString(o);
} catch (JsonProcessingException e) {
throw new RuntimeException("Couldn't serialise due to ", e);
}
})
.modelConverterFactory(() -> new ModelResolver(mapper))
.swagger(new SwaggerOptions("/swagger-ui").title("Swagger UI for Cineast Documentation"))
.reDoc(new ReDocOptions("/redoc").title("ReDoc for Cineast Documentation"));
}

/**
* Creates the base {@link OpenAPI} specification.
*
* @param config
* @return
*/
public static OpenAPI getOpenApi(APIConfig config) {
OpenAPI api = new OpenAPI();

api.info(
new Info()
.title("Cineast RESTful API")
.description("Cineast is vitrivr's content-based multimedia retrieval engine. This is it's RESTful API.")
.version(APIEndpoint.VERSION)
.license(
new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html")
)
.contact(
new Contact()
.name("Cineast Team")
.url("https://vitrivr.org")
.email("contact@vitrivr.org")
)
);

api.addTagsItem(
new Tag()
.name(APIEndpoint.namespace())
.description("Cineast Default")
);

/* Add the OAS tags */
OAS_TAGS.forEach(api::addTagsItem);

api.addServersItem(
new io.swagger.v3.oas.models.servers.Server()
.description("Cineast API Address")
.url(config.getApiAddress())
);

return api;
}

public static void writeOpenApiDocPersistently(APIEndpoint apiEndpoint, final String path) throws IOException {
try {
apiEndpoint.setHttp(apiEndpoint.dispatchService(false));
if (apiEndpoint.getOpenApi() != null) {
String schema = Json.pretty(apiEndpoint.getOpenApi().getOpenApiHandler().createOpenAPISchema());
File file = new File(path);
File folder = file.getParentFile();
if (folder != null) {
folder.mkdirs();
}
if (file.exists()) {
file.delete();
}
try (FileOutputStream stream = new FileOutputStream(
file); PrintWriter writer = new PrintWriter(stream)) {
writer.print(schema);
writer.flush();
}
LOGGER.info("Successfully stored openapi spec at {}", path);
}
} finally {
APIEndpoint.stop();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import io.javalin.http.Context;
import io.javalin.plugin.openapi.dsl.OpenApiBuilder;
import io.javalin.plugin.openapi.dsl.OpenApiDocumentation;
import org.vitrivr.cineast.api.APIEndpoint;
import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult;
import org.vitrivr.cineast.api.rest.OpenApiCompatHelper;
import org.vitrivr.cineast.api.rest.handlers.interfaces.GetRestHandler;
import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService;

Expand Down Expand Up @@ -51,7 +51,7 @@ public OpenApiDocumentation docs() {
op.summary("Find metadata for specific object id in given domain");
op.description("Find metadata for specific object id in given domain");
op.operationId("findMetadataByDomain");
op.addTagsItem(APIEndpoint.METADATA_OAS_TAG);
op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG);
})
.pathParam(DOMAIN_NAME, String.class, p -> p.description("The domain of the metadata to find"))
.pathParam(OBJECT_ID_NAME, String.class, p -> p.description("The object id of the multimedia object to find metadata for"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import io.javalin.http.Context;
import io.javalin.plugin.openapi.dsl.OpenApiBuilder;
import io.javalin.plugin.openapi.dsl.OpenApiDocumentation;
import org.vitrivr.cineast.api.APIEndpoint;
import org.vitrivr.cineast.api.messages.lookup.IdList;
import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult;
import org.vitrivr.cineast.api.rest.OpenApiCompatHelper;
import org.vitrivr.cineast.api.rest.handlers.interfaces.ParsingPostRestHandler;
import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService;

Expand Down Expand Up @@ -60,7 +60,7 @@ public OpenApiDocumentation docs() {
op.summary("Find metadata in the specified domain for all the given ids");
op.description("Find metadata in the specified domain for all the given ids");
op.operationId("findMetadataByDomainBatched");
op.addTagsItem(APIEndpoint.METADATA_OAS_TAG);
op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG);
})
.pathParam(DOMAIN_NAME, String.class, p -> p.description("The domain of the metadata to find"))
.body(inClass())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import io.javalin.http.Context;
import io.javalin.plugin.openapi.dsl.OpenApiBuilder;
import io.javalin.plugin.openapi.dsl.OpenApiDocumentation;
import org.vitrivr.cineast.api.APIEndpoint;
import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult;
import org.vitrivr.cineast.api.rest.OpenApiCompatHelper;
import org.vitrivr.cineast.api.rest.handlers.interfaces.GetRestHandler;
import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService;

Expand Down Expand Up @@ -43,7 +43,7 @@ public OpenApiDocumentation docs() {
op.summary("Find metadata for a given object id with specified key");
op.description("Find metadata for a given object id with specified key");
op.operationId("findMetadataByKey");
op.addTagsItem(APIEndpoint.METADATA_OAS_TAG);
op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG);
})
.pathParam(KEY_NAME, String.class, p -> p.description("The key of the metadata to find"))
.pathParam(OBJECT_ID_NAME, String.class, p -> p.description("The object id of for which the metadata should be find"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import io.javalin.http.Context;
import io.javalin.plugin.openapi.dsl.OpenApiBuilder;
import io.javalin.plugin.openapi.dsl.OpenApiDocumentation;
import org.vitrivr.cineast.api.APIEndpoint;
import org.vitrivr.cineast.api.messages.lookup.IdList;
import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult;
import org.vitrivr.cineast.api.rest.OpenApiCompatHelper;
import org.vitrivr.cineast.api.rest.handlers.interfaces.ParsingPostRestHandler;
import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService;

Expand Down Expand Up @@ -51,7 +51,7 @@ public OpenApiDocumentation docs() {
op.summary("Find metadata for a given object id with specified key");
op.description("Find metadata with a the speicifed key from the path across all domains and for the provided ids");
op.operationId("findMetadataByKeyBatched");
op.addTagsItem(APIEndpoint.METADATA_OAS_TAG);
op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG);
})
.pathParam(KEY_NAME, String.class, p -> p.description("The key of the metadata to find"))
.body(inClass())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import io.javalin.http.Context;
import io.javalin.plugin.openapi.dsl.OpenApiBuilder;
import io.javalin.plugin.openapi.dsl.OpenApiDocumentation;
import org.vitrivr.cineast.api.APIEndpoint;
import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult;
import org.vitrivr.cineast.api.rest.OpenApiCompatHelper;
import org.vitrivr.cineast.api.rest.handlers.interfaces.GetRestHandler;
import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService;

Expand Down Expand Up @@ -45,7 +45,7 @@ public OpenApiDocumentation docs() {
.operation(op -> {
op.description("The description");
op.summary("Find metadata for specific object id in given domain with given key");
op.addTagsItem(APIEndpoint.METADATA_OAS_TAG);
op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG);
op.operationId("findMetaFullyQualified");
})
.pathParam(OBJECT_ID_NAME, String.class, param -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import io.javalin.http.Context;
import io.javalin.plugin.openapi.dsl.OpenApiBuilder;
import io.javalin.plugin.openapi.dsl.OpenApiDocumentation;
import org.vitrivr.cineast.api.APIEndpoint;
import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult;
import org.vitrivr.cineast.api.rest.OpenApiCompatHelper;
import org.vitrivr.cineast.api.rest.handlers.interfaces.GetRestHandler;
import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService;

Expand Down Expand Up @@ -41,7 +41,7 @@ public OpenApiDocumentation docs() {
op.operationId("findMetaById");
op.description("Find metadata by the given object id");
op.summary("Find metadata for the given object id");
op.addTagsItem(APIEndpoint.METADATA_OAS_TAG);
op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG);
})
.pathParam(OBJECT_ID_NAME, String.class, p -> p.description("The object id to find metadata of"))
.json("200", outClass());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import io.javalin.http.Context;
import io.javalin.plugin.openapi.dsl.OpenApiBuilder;
import io.javalin.plugin.openapi.dsl.OpenApiDocumentation;
import org.vitrivr.cineast.api.APIEndpoint;
import org.vitrivr.cineast.api.messages.components.AbstractMetadataFilterDescriptor;
import org.vitrivr.cineast.api.messages.lookup.OptionallyFilteredIdList;
import org.vitrivr.cineast.api.messages.result.MediaObjectMetadataQueryResult;
import org.vitrivr.cineast.api.rest.OpenApiCompatHelper;
import org.vitrivr.cineast.api.rest.handlers.interfaces.ParsingPostRestHandler;
import org.vitrivr.cineast.api.rest.services.MetadataRetrievalService;
import org.vitrivr.cineast.core.data.entities.MediaObjectMetadataDescriptor;
Expand Down Expand Up @@ -58,7 +58,7 @@ public OpenApiDocumentation docs() {
op.description("Finds metadata for the given list of object ids");
op.summary("Finds metadata for the given list of object ids");
op.operationId("findMetadataForObjectIdBatched");
op.addTagsItem(APIEndpoint.METADATA_OAS_TAG);
op.addTagsItem(OpenApiCompatHelper.METADATA_OAS_TAG);
})
.body(inClass())
.json("200", outClass());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package org.vitrivr.cineast.api.rest.routes;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import io.javalin.http.Context;
import io.javalin.http.Handler;
import org.vitrivr.cineast.api.rest.resolvers.ResolutionResult;
import org.vitrivr.cineast.api.rest.resolvers.Resolver;

import io.javalin.http.Context;
import io.javalin.http.Handler;
import java.util.Map;

public class ResolvedContentRoute implements Handler {

Expand Down
Loading

0 comments on commit 4e2ed9a

Please sign in to comment.