Adding common error api responses using composite annotations avoiding repeats and clearing controllers code

This commit is contained in:
Thomas Georgios Giannos 2024-06-10 16:52:52 +03:00
parent b7afdb59ad
commit 39704dd0b2
7 changed files with 1549 additions and 695 deletions

View File

@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.xml.bind.JAXBException;
import org.opencdmp.audit.AuditableAction;
@ -24,6 +25,8 @@ import org.opencdmp.commons.enums.DmpAccessType;
import org.opencdmp.commons.enums.DmpStatus;
import org.opencdmp.commons.enums.IsActive;
import org.opencdmp.controllers.swagger.SwaggerHelpers;
import org.opencdmp.controllers.swagger.annotation.Swagger404;
import org.opencdmp.controllers.swagger.annotation.SwaggerErrorResponses;
import org.opencdmp.convention.ConventionService;
import org.opencdmp.data.StorageFileEntity;
import org.opencdmp.model.DescriptionValidationResult;
@ -72,6 +75,7 @@ import static org.opencdmp.authorization.AuthorizationFlags.Public;
@RestController
@RequestMapping(path = "api/description")
@Tag(name = "Descriptions", description = "Manage descriptions")
@SwaggerErrorResponses
public class DescriptionController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DescriptionController.class));
@ -166,7 +170,24 @@ public class DescriptionController {
}
)
}
)
),
responses = {
@ApiResponse(
description = "OK",
responseCode = "200",
content = {
@Content(
examples = {
@ExampleObject(
name = "First page",
description = "Example with the first page of paginated results",
value = SwaggerHelpers.Description.endpoint_query_response_example
)
}
)
}
)
}
)
public QueryResult<Description> query(@RequestBody DescriptionLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", Description.class.getSimpleName());
@ -183,6 +204,7 @@ public class DescriptionController {
@GetMapping("{id}")
@Operation(summary = "Fetch a specific description by id")
@Swagger404
public Description get(
@Parameter(name = "id", description = "The id of a description to fetch", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
@ -207,6 +229,7 @@ public class DescriptionController {
@PostMapping("persist")
@Operation(summary = "Create a new or update an existing description")
@Swagger404
@Transactional
@ValidationFilterAnnotation(validator = DescriptionPersist.DescriptionPersistValidator.ValidatorName, argumentName = "model")
public Description persist(
@ -228,6 +251,7 @@ public class DescriptionController {
@PostMapping("persist-status")
@Operation(summary = "Update the status of an existing description")
@Swagger404
@Transactional
@ValidationFilterAnnotation(validator = DescriptionStatusPersist.DescriptionStatusPersistValidator.ValidatorName, argumentName = "model")
public Description persistStatus(
@ -281,6 +305,7 @@ public class DescriptionController {
@DeleteMapping("{id}")
@Operation(summary = "Delete a description by id")
@Swagger404
@Transactional
public void delete(
@Parameter(name = "id", description = "The id of a description to delete", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id
@ -294,6 +319,7 @@ public class DescriptionController {
@GetMapping("{id}/export/{type}")
@Operation(summary = "Export a description in various formats by id")
@Swagger404
public ResponseEntity<byte[]> export(
@Parameter(name = "id", description = "The id of a description to export", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@Parameter(name = "type", description = "The type of the export", example = "rda", required = true) @PathVariable("type") String exportType
@ -305,6 +331,7 @@ public class DescriptionController {
@PostMapping("field-file/upload")
@Operation(summary = "Upload a file attachment on a field that supports it")
@Swagger404
@Transactional
@ValidationFilterAnnotation(validator = DescriptionFieldFilePersist.PersistValidator.ValidatorName, argumentName = "model")
public StorageFile uploadFieldFiles(
@ -327,6 +354,7 @@ public class DescriptionController {
@GetMapping("{id}/field-file/{fileId}")
@Operation(summary = "Fetch a field file attachment as byte array")
@Swagger404
public ResponseEntity<ByteArrayResource> getFieldFile(
@Parameter(name = "id", description = "The id of a description", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@Parameter(name = "fileIid", description = "The id of the file we want to fetch", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("fileId") UUID fileId
@ -353,6 +381,7 @@ public class DescriptionController {
@PostMapping("update-description-template")
@Operation(summary = "Change the template of a description")
@Swagger404
@Transactional
@ValidationFilterAnnotation(validator = UpdateDescriptionTemplatePersist.UpdateDescriptionTemplatePersistValidator.ValidatorName, argumentName = "model")
public Boolean updateDescriptionTemplate(@RequestBody UpdateDescriptionTemplatePersist model) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, IOException, JAXBException {
@ -368,6 +397,7 @@ public class DescriptionController {
@RequestMapping(method = RequestMethod.GET, value = "/xml/export/{id}", produces = "application/xml")
@Operation(summary = "Export a description in xml format by id")
@Swagger404
public @ResponseBody ResponseEntity<byte[]> getXml(
@Parameter(name = "id", description = "The id of a description to export", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable UUID id
) throws JAXBException, ParserConfigurationException, IOException, InstantiationException, IllegalAccessException, SAXException, InvalidApplicationException {

View File

@ -25,6 +25,8 @@ import org.opencdmp.commons.enums.DmpAccessType;
import org.opencdmp.commons.enums.DmpStatus;
import org.opencdmp.commons.enums.IsActive;
import org.opencdmp.controllers.swagger.SwaggerHelpers;
import org.opencdmp.controllers.swagger.annotation.Swagger404;
import org.opencdmp.controllers.swagger.annotation.SwaggerErrorResponses;
import org.opencdmp.model.DescriptionsToBeFinalized;
import org.opencdmp.model.DmpUser;
import org.opencdmp.model.DmpValidationResult;
@ -66,6 +68,7 @@ import static org.opencdmp.authorization.AuthorizationFlags.Public;
@RestController
@RequestMapping(path = "api/dmp")
@Tag(name = "Plans", description = "Manage plans")
@SwaggerErrorResponses
public class DmpController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DmpController.class));
@ -189,6 +192,7 @@ public class DmpController {
@GetMapping("{id}")
@Operation(summary = "Fetch a specific plan by id")
@Swagger404()
public Dmp Get(
@Parameter(name = "id", description = "The id of a plan to fetch", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet,
@ -213,6 +217,7 @@ public class DmpController {
@PostMapping("persist")
@Operation(summary = "Create a new or update an existing plan")
@Swagger404
@Transactional
@ValidationFilterAnnotation(validator = DmpPersist.DmpPersistValidator.ValidatorName, argumentName = "model")
public Dmp Persist(
@ -233,6 +238,7 @@ public class DmpController {
@DeleteMapping("{id}")
@Operation(summary = "Delete a plan by id")
@Swagger404
@Transactional
public void Delete(
@Parameter(name = "id", description = "The id of a plan to delete", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id
@ -246,6 +252,7 @@ public class DmpController {
@PostMapping("finalize/{id}")
@Operation(summary = "Finalize a plan by id")
@Swagger404
@Transactional
public boolean finalize(
@Parameter(name = "id", description = "The id of a plan to finalize", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@ -265,6 +272,7 @@ public class DmpController {
@GetMapping("undo-finalize/{id}")
@Operation(summary = "Undo the finalization of a plan by id (only possible if it is not already deposited)")
@Swagger404
@Transactional
public boolean undoFinalize(
@Parameter(name = "id", description = "The id of a plan to revert the finalization", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@ -302,6 +310,7 @@ public class DmpController {
@PostMapping("clone")
@Operation(summary = "Create a clone of an existing plan")
@Swagger404
@Transactional
@ValidationFilterAnnotation(validator = CloneDmpPersist.CloneDmpPersistValidator.ValidatorName, argumentName = "model")
public Dmp buildClone(
@ -324,6 +333,7 @@ public class DmpController {
@PostMapping("new-version")
@Operation(summary = "Create a new version of an existing plan")
@Swagger404
@Transactional
@ValidationFilterAnnotation(validator = NewVersionDmpPersist.NewVersionDmpPersistValidator.ValidatorName, argumentName = "model")
public Dmp createNewVersion(
@ -380,6 +390,7 @@ public class DmpController {
@GetMapping("{id}/export/{transformerId}/{type}")
@Operation(summary = "Export a plan in various formats by id")
@Swagger404
public ResponseEntity<byte[]> export(
@Parameter(name = "id", description = "The id of a plan to export", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id,
@PathVariable("transformerId") String transformerId,
@ -431,6 +442,7 @@ public class DmpController {
@RequestMapping(method = RequestMethod.GET, value = "/xml/export/{id}", produces = "application/xml")
@Operation(summary = "Export a plan in xml format by id")
@Swagger404
public @ResponseBody ResponseEntity<byte[]> getXml(
@Parameter(name = "id", description = "The id of a plan to export", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable UUID id
) throws JAXBException, ParserConfigurationException, IOException, InstantiationException, IllegalAccessException, SAXException, InvalidApplicationException {

View File

@ -0,0 +1,31 @@
package org.opencdmp.controllers.swagger.annotation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import java.lang.annotation.*;
import static org.opencdmp.controllers.swagger.SwaggerHelpers.Errors.message_403;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@ApiResponse(
description = "This is generally the response you should expect when you don't have sufficient permissions to perform an action.",
responseCode = "403",
content = {
@Content(
examples = {
@ExampleObject(
name = "404 response",
description = "This is the response in case of a 403 error.",
value = message_403
)
}
)
}
)
public @interface Swagger403 {
}

View File

@ -0,0 +1,31 @@
package org.opencdmp.controllers.swagger.annotation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import java.lang.annotation.*;
import static org.opencdmp.controllers.swagger.SwaggerHelpers.Errors.message_404;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@ApiResponse(
description = "This is generally the response you should expect when an entity is not found or you don't have sufficient permissions to view it.",
responseCode = "404",
content = {
@Content(
examples = {
@ExampleObject(
name = "404 response",
description = "This is the response in case of a 404 error where the first placeholder {0} will be replaced by the item id and the second one {1} by the item type.",
value = message_404
)
}
)
}
)
public @interface Swagger404 {
}

View File

@ -0,0 +1,31 @@
package org.opencdmp.controllers.swagger.annotation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import java.lang.annotation.*;
import static org.opencdmp.controllers.swagger.SwaggerHelpers.Errors.message_500;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
@ApiResponse(
description = "This is the response you should expect when an unexpected exception has occurred.",
responseCode = "500",
content = {
@Content(
examples = {
@ExampleObject(
name = "500 response",
description = "This is the response in case of an internal server error.",
value = message_500
)
}
)
}
)
public @interface Swagger500 {
}

View File

@ -0,0 +1,12 @@
package org.opencdmp.controllers.swagger.annotation;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Swagger500
@Swagger403
public @interface SwaggerErrorResponses {
}