diff --git a/README.md b/README.md index 6a8bfa6..993b559 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,9 @@ For more details see [README.md](ontology-generator/README.md) The data are mapped from Java objects to RDF entities via ontological mapping library JOPA and stored in a local GraphDB database. The database URL needs to be configured in `application.yml`. The repository first needs to be created. + +## API Documentation + +You can access the Swagger UI at the following URL: `http://localhost:9999/swagger-ui.html` + +The OpenAPI documentation for the API can be accessed at: `http://localhost:9999/v1/api-docs` \ No newline at end of file diff --git a/build.gradle b/build.gradle index a90dce9..56f7958 100644 --- a/build.gradle +++ b/build.gradle @@ -48,6 +48,8 @@ dependencies { implementation 'com.fasterxml:classmate:1.5.0' implementation 'com.opencsv:opencsv:5.3' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0' + implementation 'org.projectlombok:lombok:1.18.30' annotationProcessor 'org.projectlombok:lombok:1.18.30' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' diff --git a/src/main/java/cz/cvut/kbss/analysis/config/OpenApiConfig.java b/src/main/java/cz/cvut/kbss/analysis/config/OpenApiConfig.java new file mode 100644 index 0000000..7e1476b --- /dev/null +++ b/src/main/java/cz/cvut/kbss/analysis/config/OpenApiConfig.java @@ -0,0 +1,30 @@ +package cz.cvut.kbss.analysis.config; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.security.SecurityScheme; +import io.swagger.v3.oas.annotations.security.SecuritySchemes; + +/** + * Configuration class for OpenAPI documentation. + */ +@OpenAPIDefinition( + info = @Info( + title = "FTA and FMEA API", + description = "Docs for FTA and FMEA API", + version = "1.0" + ) +) +@SecuritySchemes({ + @SecurityScheme( + name = "basicAuth", + description = "Basic auth", + scheme = "basic", + type = SecuritySchemeType.HTTP, + in = SecuritySchemeIn.HEADER + ) +}) +public class OpenApiConfig { +} diff --git a/src/main/java/cz/cvut/kbss/analysis/controller/ComponentController.java b/src/main/java/cz/cvut/kbss/analysis/controller/ComponentController.java index 15156b6..a6778f1 100755 --- a/src/main/java/cz/cvut/kbss/analysis/controller/ComponentController.java +++ b/src/main/java/cz/cvut/kbss/analysis/controller/ComponentController.java @@ -9,6 +9,9 @@ import cz.cvut.kbss.analysis.service.IdentifierService; import cz.cvut.kbss.analysis.util.Vocabulary; import cz.cvut.kbss.jsonld.JsonLd; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -31,11 +34,20 @@ public class ComponentController { private final ComponentRepositoryService repositoryService; private final IdentifierService identifierService; + @Operation(summary = "Retrieve all components") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Retrieved all components") + }) @GetMapping(produces = {JsonLd.MEDIA_TYPE, MediaType.APPLICATION_JSON_VALUE}) public List findAll() { return repositoryService.findAll(); } + + @Operation(summary = "Create a new component") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Component created"), + }) @ResponseStatus(HttpStatus.CREATED) @PostMapping(consumes = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) public Component create(@RequestBody Component component) { @@ -44,12 +56,21 @@ public Component create(@RequestBody Component component) { return component; } + @Operation(summary = "Update an existing component") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Component updated"), + }) @PutMapping(consumes = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}, produces = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) public Component update(@RequestBody ComponentUpdateDTO componentUpdate) { log.info("> update - {}", componentUpdate); return repositoryService.updateByDTO(componentUpdate); } + @Operation(summary = "Delete a component") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Component deleted"), + @ApiResponse(responseCode = "404", description = "Component not found") + }) @ResponseStatus(HttpStatus.NO_CONTENT) @DeleteMapping(value = "/{componentFragment}") public void delete(@PathVariable(name = "componentFragment") String componentFragment) { @@ -59,6 +80,11 @@ public void delete(@PathVariable(name = "componentFragment") String componentFra repositoryService.remove(componentUri); } + @Operation(summary = "Retrieve functions of a component") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Functions retrieved"), + @ApiResponse(responseCode = "404", description = "Component not found") + }) @GetMapping(value = "/{componentFragment}/functions", produces = {JsonLd.MEDIA_TYPE, MediaType.APPLICATION_JSON_VALUE}) public Set getFunctions(@PathVariable(name = "componentFragment") String componentFragment) { log.info("> getFunctions - {}", componentFragment); @@ -66,6 +92,11 @@ public Set getFunctions(@PathVariable(name = "componentFragment") Stri return repositoryService.getFunctions(componentUri); } + @Operation(summary = "Retrieve failure modes of a component") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Failure modes retrieved"), + @ApiResponse(responseCode = "404", description = "Component not found") + }) @GetMapping(value = "/{componentFragment}/failureModes", produces = {JsonLd.MEDIA_TYPE, MediaType.APPLICATION_JSON_VALUE}) public Set getFailureModes(@PathVariable(name = "componentFragment") String componentFragment) { log.info("> getFailureModes - {}", componentFragment); @@ -73,15 +104,26 @@ public Set getFailureModes(@PathVariable(name = "componentFragment" return repositoryService.getFailureModes(componentUri); } + + @Operation(summary = "Add new failure mode to a component") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Failure mode added"), + @ApiResponse(responseCode = "404", description = "Component not found") + }) @ResponseStatus(HttpStatus.CREATED) @PostMapping(value = "/{componentFragment}/failureModes", produces = {JsonLd.MEDIA_TYPE, MediaType.APPLICATION_JSON_VALUE}, consumes = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) public FailureMode addFailureMode(@PathVariable(name = "componentFragment") String componentFragment, @RequestBody FailureMode failureMode) { log.info("> addFailureMode - {}, {}", componentFragment, failureMode); URI componentUri = identifierService.composeIdentifier(Vocabulary.s_c_component, componentFragment); - return repositoryService.addFailureMode(componentUri,failureMode); + return repositoryService.addFailureMode(componentUri, failureMode); } + @Operation(summary = "Add a failure mode by URI to a component") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Failure mode added"), + @ApiResponse(responseCode = "404", description = "Component or failure mode not found") + }) @ResponseStatus(HttpStatus.CREATED) @PostMapping(value = "/{componentFragment}/failureModes/{failureModeFragment}", produces = {JsonLd.MEDIA_TYPE, MediaType.APPLICATION_JSON_VALUE}, consumes = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) public void addFailureModeByURI(@PathVariable(name = "componentFragment") String componentFragment, @PathVariable(name = "failureModeFragment") String failureModeFragment) { @@ -91,6 +133,11 @@ public void addFailureModeByURI(@PathVariable(name = "componentFragment") String repositoryService.addFailureModeByUri(componentUri, failureModeUri); } + @Operation(summary = "Delete a failure mode from a component") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Failure mode deleted "), + @ApiResponse(responseCode = "404", description = "Component or failure mode not found") + }) @DeleteMapping(value = "/{componentFragment}/failureModes/{failureModeFragment}") public void deleteFailureMode(@PathVariable(name = "componentFragment") String componentFragment, @PathVariable(name = "failureModeFragment") String failureModeFragment) { log.info("> deleteFailureMode - {}, {}", componentFragment, failureModeFragment); @@ -101,6 +148,11 @@ public void deleteFailureMode(@PathVariable(name = "componentFragment") String c log.info("< deleteFailureMode"); } + @Operation(summary = "Add a function to a component") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Function added"), + @ApiResponse(responseCode = "404", description = "Component not found") + }) @ResponseStatus(HttpStatus.CREATED) @PostMapping(value = "/{componentFragment}/functions", consumes = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) public Function addFunction(@PathVariable(name = "componentFragment") String componentFragment, @RequestBody Function function) { @@ -110,16 +162,27 @@ public Function addFunction(@PathVariable(name = "componentFragment") String com return repositoryService.addFunction(componentUri, function); } + + @Operation(summary = "Add function by URI to a component") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Function added to the component"), + @ApiResponse(responseCode = "404", description = "Component or Function not found"), + }) @ResponseStatus(HttpStatus.CREATED) @PostMapping(value = "/{componentFragment}/functions/{functionFragment}", produces = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) public Function addFunctionByURI(@PathVariable(name = "componentFragment") String componentFragment, @PathVariable(name = "functionFragment") String functionFragment) { log.info("> addFunction - {}, {}", componentFragment, functionFragment); URI componentUri = identifierService.composeIdentifier(Vocabulary.s_c_component, componentFragment); URI functionUri = identifierService.composeIdentifier(Vocabulary.s_c_function, functionFragment); - + return repositoryService.addFunctionByURI(componentUri, functionUri); } + @Operation(summary = "Add a function by URI to a component") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Function added by URI"), + @ApiResponse(responseCode = "404", description = "Component or function not found") + }) @DeleteMapping(value = "/{componentFragment}/functions/{functionFragment}") public void deleteFunction(@PathVariable(name = "componentFragment") String componentFragment, @PathVariable(name = "functionFragment") String functionFragment) { log.info("> deleteFunction - {}, {}", componentFragment, functionFragment); @@ -130,6 +193,11 @@ public void deleteFunction(@PathVariable(name = "componentFragment") String comp log.info("< deleteFunction"); } + @Operation(summary = "Link two components") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Components linked"), + @ApiResponse(responseCode = "404", description = "Component not found") + }) @PostMapping(value = "/{componentFragment}/linkComponent/{linkFragment}") public Component linkComponents( @PathVariable(name = "componentFragment") String componentFragment, @@ -141,6 +209,11 @@ public Component linkComponents( return repositoryService.linkComponents(componentUri, linkComponentUri); } + @Operation(summary = "Unlink a component from its linked components") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Component unlinked"), + @ApiResponse(responseCode = "404", description = "Component not found") + }) @DeleteMapping(value = "/{componentFragment}/linkComponent") public void unlinkComponents(@PathVariable(name = "componentFragment") String componentFragment) { log.info("> unlinkComponents - {}", componentFragment); @@ -150,9 +223,14 @@ public void unlinkComponents(@PathVariable(name = "componentFragment") String co log.info("< unlinkComponents"); } + @Operation(summary = "Merge two components into one") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Components merged"), + @ApiResponse(responseCode = "404", description = "One or both components not found") + }) @PostMapping(value = "/mergeComponents/{sourceFragment}/{targetFragment}") public void mergeComponents(@PathVariable(name = "sourceFragment") String sourceFragment - ,@PathVariable(name = "targetFragment") String targetFragment){ + , @PathVariable(name = "targetFragment") String targetFragment) { log.info("> mergeComponents - {} {}", sourceFragment, targetFragment); URI sourceUri = identifierService.composeIdentifier(Vocabulary.s_c_component, sourceFragment); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8af6507..d5226ed 100755 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -42,4 +42,10 @@ operational.data.filter: min-operational-hours: 200 operationalFailureRateService: http://localhost:9998/stats/failure-rate -fhaBasedoperationalFailureRateService: http://localhost:9998/stats/fha-failure-rate \ No newline at end of file +fhaBasedoperationalFailureRateService: http://localhost:9998/stats/fha-failure-rate + +springdoc: + api-docs: + path: /v1/api-docs + swagger-ui: + path: /swagger-ui.html