diff --git a/src/main/java/it/gov/innovazione/ndc/Application.java b/src/main/java/it/gov/innovazione/ndc/Application.java index 4a21889..e0abdbd 100644 --- a/src/main/java/it/gov/innovazione/ndc/Application.java +++ b/src/main/java/it/gov/innovazione/ndc/Application.java @@ -1,5 +1,9 @@ package it.gov.innovazione.ndc; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Contact; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.info.License; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @@ -7,6 +11,34 @@ import java.time.Clock; @SpringBootApplication +@OpenAPIDefinition( + info = @Info( + title = "Schema - Semantic Backend", + version = "0.0.1", + description = """ + This API exposes information from Schema, the National Data Catalog for Semantic Interoperability including the REST API + for accessing controlled vocabularies. + + + It is used as a backend service for the [schema.gov.it](https://schema.gov.it) website and to expose functionalities in + an interoperable way. + + + Provided information can be used to discover ontologies, controlled vocabularies and schemas indexed by Schema, and to + ease the creation of semantically interoperable digital services such as web forms and APIs. + + + **This API is a beta release, and it can change in the future during the consolidation phase of Schema.**""", + contact = @Contact( + name = "Dipartimento per la Trasformazione digitale", + email = "info@teamdigitale.governo.it"), + license = @License( + name = " BSD-3-Clause", + url = "https://opensource.org/licenses/BSD-3-Clause"), + summary = "Expose ontology, controlled vocabularies and schemas information from Schema." + + + )) public class Application { public static void main(String[] args) { diff --git a/src/main/java/it/gov/innovazione/ndc/alerter/controller/AbstractCrudController.java b/src/main/java/it/gov/innovazione/ndc/alerter/controller/AbstractCrudController.java index 1fb5fc1..91576d4 100644 --- a/src/main/java/it/gov/innovazione/ndc/alerter/controller/AbstractCrudController.java +++ b/src/main/java/it/gov/innovazione/ndc/alerter/controller/AbstractCrudController.java @@ -1,6 +1,7 @@ package it.gov.innovazione.ndc.alerter.controller; +import io.swagger.v3.oas.annotations.Operation; import it.gov.innovazione.ndc.alerter.data.EntityService; import it.gov.innovazione.ndc.alerter.dto.SlimPager; import it.gov.innovazione.ndc.alerter.entities.Nameable; @@ -27,6 +28,10 @@ public abstract class AbstractCrudController getEntityService(); @GetMapping + @Operation( + operationId = "getAll", + description = "Get all entities", + summary = "Get all entities") public SlimPager getPaginated(Pageable pageable) { return toSlimPager(getEntityService().getPaginated(pageable)); } @@ -50,12 +55,20 @@ private SlimPager toSlimPager(Page paginated) { } @GetMapping("{id}") + @Operation( + operationId = "getOne", + description = "Get one entity", + summary = "Get one entity") public D getOne(@PathVariable String id) { return getEntityService().getById(id); } @PostMapping @ResponseStatus(CREATED) + @Operation( + operationId = "create", + description = "Create a new entity", + summary = "Create a new entity") public D create(@Valid @RequestBody D dto) { handlePreCreate(dto); D createdEntity = getEntityService().create(dto); @@ -73,6 +86,10 @@ protected void handlePostCreate(D createdEntity) { @PatchMapping @ResponseStatus(CREATED) + @Operation( + operationId = "update", + description = "Update an entity", + summary = "Update an entity") public D update(@Valid @RequestBody D dto) { handlePreUpdate(dto); D updatedDto = getEntityService().update(dto); @@ -90,6 +107,10 @@ protected void handlePostUpdate(D updatedDto) { @DeleteMapping("{id}") @ResponseStatus(CREATED) + @Operation( + operationId = "delete", + description = "Delete an entity", + summary = "Delete an entity") public void delete(@PathVariable String id) { handlePreDelete(id); D deletedDto = getEntityService().delete(id); diff --git a/src/main/java/it/gov/innovazione/ndc/controller/ApplicationStatusController.java b/src/main/java/it/gov/innovazione/ndc/controller/ApplicationStatusController.java index ec056b4..4b0114b 100644 --- a/src/main/java/it/gov/innovazione/ndc/controller/ApplicationStatusController.java +++ b/src/main/java/it/gov/innovazione/ndc/controller/ApplicationStatusController.java @@ -1,5 +1,7 @@ package it.gov.innovazione.ndc.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import it.gov.innovazione.ndc.gen.dto.Problem; import it.gov.innovazione.ndc.model.Builders; import lombok.RequiredArgsConstructor; @@ -15,27 +17,33 @@ @RestController @RequiredArgsConstructor +@Tag(name = "status", description = "Entry point for application status") public class ApplicationStatusController { private final HealthEndpoint healthEndpoint; @GetMapping("/status") + @Operation( + operationId = "checkStatus", + description = "Check if the application is available and healthy", + tags = {"status"}, + summary = "Check the application status") public ResponseEntity getStatus() { Status status = healthEndpoint.health().getStatus(); if (status != Status.UP) { Problem response = Builders.problem() - .status(INTERNAL_SERVER_ERROR) - .title("Application is not available") - .build(); + .status(INTERNAL_SERVER_ERROR) + .title("Application is not available") + .build(); return ResponseEntity - .status(INTERNAL_SERVER_ERROR) - .contentType(MediaType.APPLICATION_PROBLEM_JSON) - .body(response); + .status(INTERNAL_SERVER_ERROR) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .body(response); } return ResponseEntity.status(OK.value()) - .contentType(MediaType.APPLICATION_PROBLEM_JSON) - .body(Builders.problem() - .status(OK) - .title("Application is available").build()); + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .body(Builders.problem() + .status(OK) + .title("Application is available").build()); } } diff --git a/src/main/java/it/gov/innovazione/ndc/controller/CheckUrlController.java b/src/main/java/it/gov/innovazione/ndc/controller/CheckUrlController.java index 8817934..4729544 100644 --- a/src/main/java/it/gov/innovazione/ndc/controller/CheckUrlController.java +++ b/src/main/java/it/gov/innovazione/ndc/controller/CheckUrlController.java @@ -1,5 +1,9 @@ package it.gov.innovazione.ndc.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -16,8 +20,20 @@ @RequestMapping("check-url") @Slf4j public class CheckUrlController { + @GetMapping @SneakyThrows + @Operation( + operationId = "checkUrl", + description = "Check if the passed URL is available", + summary = "Check the URL status", + responses = { + @ApiResponse(responseCode = "200", description = "The URL is available", + content = @Content(schema = @Schema(implementation = HttpStatus.class))), + @ApiResponse(responseCode = "404", description = "The URL is not available", + content = @Content(schema = @Schema(implementation = HttpStatus.class))), + @ApiResponse(responseCode = "500", description = "The URL is not available", + content = @Content(schema = @Schema(implementation = HttpStatus.class)))}) public ResponseEntity check(@RequestParam String url) { log.info("Checking url {}", url); HttpURLConnection huc = (HttpURLConnection) new URL(url).openConnection(); diff --git a/src/main/java/it/gov/innovazione/ndc/controller/ConfigurationController.java b/src/main/java/it/gov/innovazione/ndc/controller/ConfigurationController.java index 7660195..8e1f474 100644 --- a/src/main/java/it/gov/innovazione/ndc/controller/ConfigurationController.java +++ b/src/main/java/it/gov/innovazione/ndc/controller/ConfigurationController.java @@ -1,5 +1,6 @@ package it.gov.innovazione.ndc.controller; +import io.swagger.v3.oas.annotations.Operation; import it.gov.innovazione.ndc.eventhandler.NdcEventPublisher; import it.gov.innovazione.ndc.eventhandler.event.ConfigService; import it.gov.innovazione.ndc.harvester.service.ActualConfigService; @@ -32,6 +33,10 @@ public class ConfigurationController { private final NdcEventPublisher eventPublisher; @GetMapping + @Operation( + operationId = "getConfig", + description = "Get the configuration for a repository", + summary = "Get the configuration for a repository") public Map getConfig( @PathVariable String repoId) { if (repoId.equals("ndc")) { @@ -42,6 +47,10 @@ public Map getConfig( @PostMapping @ResponseStatus(CREATED) + @Operation( + operationId = "setConfig", + description = "Set the configuration for a repository", + summary = "Set the configuration for a repository") public void setConfig( @PathVariable String repoId, @RequestBody Map config, @@ -55,6 +64,10 @@ public void setConfig( @PutMapping("/{configKey}") @ResponseStatus(ACCEPTED) + @Operation( + operationId = "updateRepository", + description = "Update a configuration key for a repository", + summary = "Update a configuration key for a repository") public void updateRepository( @PathVariable String repoId, @PathVariable ActualConfigService.ConfigKey configKey, @@ -69,6 +82,10 @@ public void updateRepository( @DeleteMapping("/{configKey}") @ResponseStatus(ACCEPTED) + @Operation( + operationId = "deleteRepository", + description = "Delete a configuration key for a repository", + summary = "Delete a configuration key for a repository") public void deleteRepository( @PathVariable String repoId, @PathVariable ActualConfigService.ConfigKey configKey, diff --git a/src/main/java/it/gov/innovazione/ndc/controller/HarvestJobController.java b/src/main/java/it/gov/innovazione/ndc/controller/HarvestJobController.java index 51012a9..000584c 100644 --- a/src/main/java/it/gov/innovazione/ndc/controller/HarvestJobController.java +++ b/src/main/java/it/gov/innovazione/ndc/controller/HarvestJobController.java @@ -1,5 +1,6 @@ package it.gov.innovazione.ndc.controller; +import io.swagger.v3.oas.annotations.Operation; import it.gov.innovazione.ndc.alerter.entities.EventCategory; import it.gov.innovazione.ndc.alerter.entities.Severity; import it.gov.innovazione.ndc.alerter.event.AlertableEvent; @@ -40,6 +41,10 @@ public class HarvestJobController { private final NdcEventPublisher eventPublisher; @PostMapping("jobs/harvest") + @Operation( + operationId = "startHarvestJob", + description = "Start a new harvest job", + summary = "Start a new harvest job") public List startHarvestJob(@RequestParam(required = false, defaultValue = "false") Boolean force) { log.info("Starting Harvest job at " + LocalDateTime.now()); List harvest = harvesterJob.harvest(force); @@ -53,16 +58,28 @@ public List startHarvestJob(@RequestParam(required = false } @GetMapping("jobs/harvest/run") + @Operation( + operationId = "getHarvestRuns", + description = "Get all harvest runs", + summary = "Get all harvest runs") public List getAllRuns() { return harvesterRunService.getAllRuns(); } @GetMapping("jobs/harvest/running") + @Operation( + operationId = "getRunningInstances", + description = "Get all running instances", + summary = "Get all running instances") public List getAllRunningInstance() { return harvesterRunService.getAllRunningInstances(); } @DeleteMapping("jobs/harvest/run") + @Operation( + operationId = "deletePendingRuns", + description = "Delete all pending runs", + summary = "Delete all pending runs") public void deletePendingRuns() { harvesterRunService.deletePendingRuns(); eventPublisher.publishAlertableEvent( @@ -73,6 +90,10 @@ public void deletePendingRuns() { } @PostMapping(value = "jobs/harvest", params = "repositoryId") + @Operation( + operationId = "harvestRepositories", + description = "Harvest a specific repository", + summary = "Harvest a specific repository") public JobExecutionResponse harvestRepositories( @RequestParam("repositoryId") String repositoryId, @RequestParam(required = false, defaultValue = "") String revision, @@ -90,6 +111,10 @@ public JobExecutionResponse harvestRepositories( @PostMapping("jobs/clear") @ResponseStatus(HttpStatus.ACCEPTED) + @Operation( + operationId = "clearRepo", + description = "Clear a repository", + summary = "Clear a repository") public void clearRepo(@RequestParam("repo_url") String repoUrl) { if (StringUtils.isEmpty(repoUrl)) { throw new IllegalArgumentException("repo_url is required"); diff --git a/src/main/java/it/gov/innovazione/ndc/controller/RepositoryController.java b/src/main/java/it/gov/innovazione/ndc/controller/RepositoryController.java index 1799e13..f8699eb 100644 --- a/src/main/java/it/gov/innovazione/ndc/controller/RepositoryController.java +++ b/src/main/java/it/gov/innovazione/ndc/controller/RepositoryController.java @@ -1,5 +1,6 @@ package it.gov.innovazione.ndc.controller; +import io.swagger.v3.oas.annotations.Operation; import it.gov.innovazione.ndc.alerter.entities.EventCategory; import it.gov.innovazione.ndc.alerter.entities.Severity; import it.gov.innovazione.ndc.alerter.event.DefaultAlertableEvent; @@ -43,6 +44,10 @@ public class RepositoryController { private final NdcEventPublisher eventPublisher; @GetMapping + @Operation( + operationId = "getAllRepositories", + description = "Get all repositories", + summary = "Get all repositories") public List getAllRepositories() { return repositoryService.getActiveRepos(); } @@ -50,6 +55,10 @@ public List getAllRepositories() { @PostMapping @ResponseStatus(CREATED) @SneakyThrows + @Operation( + operationId = "createRepository", + description = "Create a new repository", + summary = "Create a new repository") public void createRepository( @RequestBody CreateRepository repository, Principal principal) { @@ -86,6 +95,10 @@ private void assertValidUrl(@RequestBody CreateRepository repository) throws Bad @PatchMapping("/{id}") @SneakyThrows + @Operation( + operationId = "updateRepository", + description = "Update a repository", + summary = "Update a repository") public ResponseEntity updateRepository( @PathVariable String id, @RequestBody CreateRepository repository, @@ -119,6 +132,10 @@ public ResponseEntity updateRepository( @DeleteMapping("/{id}") @SneakyThrows + @Operation( + operationId = "deleteRepository", + description = "Delete a repository", + summary = "Delete a repository") public ResponseEntity deleteRepository( @PathVariable String id, Principal principal) { diff --git a/src/main/java/it/gov/innovazione/ndc/controller/ValidationController.java b/src/main/java/it/gov/innovazione/ndc/controller/ValidationController.java index 453b158..7df305d 100644 --- a/src/main/java/it/gov/innovazione/ndc/controller/ValidationController.java +++ b/src/main/java/it/gov/innovazione/ndc/controller/ValidationController.java @@ -1,5 +1,6 @@ package it.gov.innovazione.ndc.controller; +import io.swagger.v3.oas.annotations.Operation; import it.gov.innovazione.ndc.service.ValidationService; import it.gov.innovazione.ndc.validator.ValidationResultDto; import lombok.RequiredArgsConstructor; @@ -18,6 +19,10 @@ public class ValidationController { private final ValidationService validationService; @PostMapping + @Operation( + operationId = "validateFile", + description = "Validate the file representing a semantic asset", + summary = "Validate the file") public ResponseEntity validateFile(@RequestParam(value = "type") String assetType, @RequestParam(value = "file") MultipartFile file) { return AppJsonResponse.ok(validationService.validate(file, assetType)); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index eb2d351..6b1aec8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -25,9 +25,8 @@ harvester.controlled-vocabulary.scanner.skip-words=transparency-obligation-organ harvester.auth.user=${HARVESTER_USER:harv-user} harvester.auth.password=${HARVESTER_PASSWORD:harv-password} - -springdoc.api-docs.enabled=false -springdoc.swagger-ui.url=/openapi.yaml +springdoc.api-docs.enabled=true +#springdoc.swagger-ui.url=/openapi.yaml #Disable restrictions on multipart requests to validate semantic assets files spring.servlet.multipart.max-file-size=-1 spring.servlet.multipart.max-request-size=-1