Adding swagger docs for tag endpoints, dmp renames on swagger for current api

This commit is contained in:
Thomas Georgios Giannos 2024-07-04 10:50:36 +03:00
parent f2c9120d0c
commit 5e9503c291
5 changed files with 304 additions and 18 deletions

View File

@ -59,9 +59,9 @@ import java.util.UUID;
@RequestMapping(path = "api/dmp-blueprint") @RequestMapping(path = "api/dmp-blueprint")
@Tag(name = "Plan Blueprints", description = "Manage plan blueprints") @Tag(name = "Plan Blueprints", description = "Manage plan blueprints")
@SwaggerCommonErrorResponses @SwaggerCommonErrorResponses
public class DmpBlueprintController { public class PlanBlueprintController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DmpBlueprintController.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PlanBlueprintController.class));
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
@ -75,7 +75,7 @@ public class DmpBlueprintController {
private final MessageSource messageSource; private final MessageSource messageSource;
public DmpBlueprintController( public PlanBlueprintController(
BuilderFactory builderFactory, BuilderFactory builderFactory,
AuditService auditService, AuditService auditService,
DmpBlueprintService dmpBlueprintService, DmpBlueprintService dmpBlueprintService,
@ -91,12 +91,12 @@ public class DmpBlueprintController {
} }
@PostMapping("query") @PostMapping("query")
@OperationWithTenantHeader(summary = "Query all plan blueprints", description = SwaggerHelpers.DmpBlueprint.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.DmpBlueprint.endpoint_query_request_body, content = @Content( @OperationWithTenantHeader(summary = "Query all plan blueprints", description = SwaggerHelpers.PlanBlueprint.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.PlanBlueprint.endpoint_query_request_body, content = @Content(
examples = { examples = {
@ExampleObject( @ExampleObject(
name = "Pagination and projection", name = "Pagination and projection",
description = "Simple paginated request using a property projection list and pagination info", description = "Simple paginated request using a property projection list and pagination info",
value = SwaggerHelpers.DmpBlueprint.endpoint_query_request_body_example value = SwaggerHelpers.PlanBlueprint.endpoint_query_request_body_example
) )
} }
)), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content( )), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
@ -108,7 +108,7 @@ public class DmpBlueprintController {
examples = @ExampleObject( examples = @ExampleObject(
name = "First page", name = "First page",
description = "Example with the first page of paginated results", description = "Example with the first page of paginated results",
value = SwaggerHelpers.DmpBlueprint.endpoint_query_response_example value = SwaggerHelpers.PlanBlueprint.endpoint_query_response_example
)))) ))))
public QueryResult<DmpBlueprint> query(@RequestBody DmpBlueprintLookup lookup) throws MyApplicationException, MyForbiddenException { public QueryResult<DmpBlueprint> query(@RequestBody DmpBlueprintLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", DmpBlueprint.class.getSimpleName()); logger.debug("querying {}", DmpBlueprint.class.getSimpleName());

View File

@ -73,9 +73,9 @@ import static org.opencdmp.authorization.AuthorizationFlags.Public;
@RequestMapping(path = "api/dmp") @RequestMapping(path = "api/dmp")
@Tag(name = "Plans", description = "Manage plans") @Tag(name = "Plans", description = "Manage plans")
@SwaggerCommonErrorResponses @SwaggerCommonErrorResponses
public class DmpController { public class PlanController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DmpController.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PlanController.class));
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
@ -91,7 +91,7 @@ public class DmpController {
private final ElasticQueryHelperService elasticQueryHelperService; private final ElasticQueryHelperService elasticQueryHelperService;
public DmpController( public PlanController(
BuilderFactory builderFactory, BuilderFactory builderFactory,
AuditService auditService, AuditService auditService,
DmpService dmpService, DmpService dmpService,
@ -147,12 +147,12 @@ public class DmpController {
} }
@PostMapping("query") @PostMapping("query")
@OperationWithTenantHeader(summary = "Query all plans", description = SwaggerHelpers.Dmp.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.Dmp.endpoint_query_request_body, content = @Content( @OperationWithTenantHeader(summary = "Query all plans", description = SwaggerHelpers.Plan.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.Plan.endpoint_query_request_body, content = @Content(
examples = { examples = {
@ExampleObject( @ExampleObject(
name = "Pagination and projection", name = "Pagination and projection",
description = "Simple paginated request using a property projection list and pagination info", description = "Simple paginated request using a property projection list and pagination info",
value = SwaggerHelpers.Dmp.endpoint_query_request_body_example value = SwaggerHelpers.Plan.endpoint_query_request_body_example
) )
} }
)), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content( )), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
@ -164,7 +164,7 @@ public class DmpController {
examples = @ExampleObject( examples = @ExampleObject(
name = "First page", name = "First page",
description = "Example with the first page of paginated results", description = "Example with the first page of paginated results",
value = SwaggerHelpers.Dmp.endpoint_query_response_example value = SwaggerHelpers.Plan.endpoint_query_response_example
)))) ))))
public QueryResult<Dmp> Query(@RequestBody DmpLookup lookup) throws MyApplicationException, MyForbiddenException { public QueryResult<Dmp> Query(@RequestBody DmpLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", Dmp.class.getSimpleName()); logger.debug("querying {}", Dmp.class.getSimpleName());

View File

@ -11,8 +11,19 @@ import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import gr.cite.tools.validation.ValidationFilterAnnotation; import gr.cite.tools.validation.ValidationFilterAnnotation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.opencdmp.audit.AuditableAction; import org.opencdmp.audit.AuditableAction;
import org.opencdmp.authorization.AuthorizationFlags; import org.opencdmp.authorization.AuthorizationFlags;
import org.opencdmp.controllers.swagger.SwaggerHelpers;
import org.opencdmp.controllers.swagger.annotation.OperationWithTenantHeader;
import org.opencdmp.controllers.swagger.annotation.Swagger400;
import org.opencdmp.controllers.swagger.annotation.Swagger404;
import org.opencdmp.controllers.swagger.annotation.SwaggerCommonErrorResponses;
import org.opencdmp.data.TagEntity; import org.opencdmp.data.TagEntity;
import org.opencdmp.model.Tag; import org.opencdmp.model.Tag;
import org.opencdmp.model.builder.TagBuilder; import org.opencdmp.model.builder.TagBuilder;
@ -33,6 +44,8 @@ import java.util.*;
@RestController @RestController
@RequestMapping(path = "api/tag") @RequestMapping(path = "api/tag")
@io.swagger.v3.oas.annotations.tags.Tag(name = "Tags", description = "Manage tags")
@SwaggerCommonErrorResponses
public class TagController { public class TagController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TagController.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TagController.class));
@ -65,6 +78,25 @@ public class TagController {
} }
@PostMapping("query") @PostMapping("query")
@OperationWithTenantHeader(summary = "Query all tags", description = SwaggerHelpers.Tag.endpoint_query, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = SwaggerHelpers.Tag.endpoint_query_request_body, content = @Content(
examples = {
@ExampleObject(
name = "Pagination and projection",
description = "Simple paginated request using a property projection list and pagination info",
value = SwaggerHelpers.Tag.endpoint_query_request_body_example
)
}
)), responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
array = @ArraySchema(
schema = @Schema(
implementation = Tag.class
)
),
examples = @ExampleObject(
name = "First page",
description = "Example with the first page of paginated results",
value = SwaggerHelpers.Tag.endpoint_query_response_example
))))
public QueryResult<Tag> Query(@RequestBody TagLookup lookup) throws MyApplicationException, MyForbiddenException { public QueryResult<Tag> Query(@RequestBody TagLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", Tag.class.getSimpleName()); logger.debug("querying {}", Tag.class.getSimpleName());
@ -82,7 +114,18 @@ public class TagController {
} }
@GetMapping("{id}") @GetMapping("{id}")
public Tag Get(@PathVariable("id") UUID id, FieldSet fieldSet, Locale locale) throws MyApplicationException, MyForbiddenException, MyNotFoundException { @OperationWithTenantHeader(summary = "Fetch a specific tag by id", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = Tag.class
))
))
@Swagger404
public Tag Get(
@Parameter(name = "id", description = "The id of a tag 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,
Locale locale
) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving" + Tag.class.getSimpleName()).And("id", id).And("fields", fieldSet)); logger.debug(new MapLogEntry("retrieving" + Tag.class.getSimpleName()).And("id", id).And("fields", fieldSet));
this.censorFactory.censor(TagCensor.class).censor(fieldSet, null); this.censorFactory.censor(TagCensor.class).censor(fieldSet, null);
@ -101,9 +144,20 @@ public class TagController {
} }
@PostMapping("persist") @PostMapping("persist")
@OperationWithTenantHeader(summary = "Create a new or update an existing tag", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200", content = @Content(
schema = @Schema(
implementation = Tag.class
))
))
@Swagger400
@Swagger404
@Transactional @Transactional
@ValidationFilterAnnotation(validator = TagPersist.TagPersistValidator.ValidatorName, argumentName = "model") @ValidationFilterAnnotation(validator = TagPersist.TagPersistValidator.ValidatorName, argumentName = "model")
public Tag Persist(@RequestBody TagPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException { public Tag Persist(
@RequestBody TagPersist model,
@Parameter(name = "fieldSet", description = SwaggerHelpers.Commons.fieldset_description, required = true) FieldSet fieldSet
) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException {
logger.debug(new MapLogEntry("persisting" + Tag.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); logger.debug(new MapLogEntry("persisting" + Tag.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet));
Tag persisted = this.tagService.persist(model, fieldSet); Tag persisted = this.tagService.persist(model, fieldSet);
@ -116,8 +170,13 @@ public class TagController {
} }
@DeleteMapping("{id}") @DeleteMapping("{id}")
@OperationWithTenantHeader(summary = "Delete a tag by id", description = "",
responses = @ApiResponse(description = "OK", responseCode = "200"))
@Swagger404
@Transactional @Transactional
public void Delete(@PathVariable("id") UUID id) throws MyForbiddenException, InvalidApplicationException { public void Delete(
@Parameter(name = "id", description = "The id of a tag to delete", example = "c0c163dc-2965-45a5-9608-f76030578609", required = true) @PathVariable("id") UUID id
) throws MyForbiddenException, InvalidApplicationException {
logger.debug(new MapLogEntry("retrieving" + Tag.class.getSimpleName()).And("id", id)); logger.debug(new MapLogEntry("retrieving" + Tag.class.getSimpleName()).And("id", id));
this.tagService.deleteAndSave(id); this.tagService.deleteAndSave(id);

View File

@ -51,7 +51,7 @@ public class SwaggerHelpers {
} }
public static class Dmp { public static class Plan {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -2307,7 +2307,7 @@ public class SwaggerHelpers {
} }
public static class DmpBlueprint { public static class PlanBlueprint {
public static final String endpoint_query = public static final String endpoint_query =
""" """
@ -2859,4 +2859,231 @@ public class SwaggerHelpers {
} }
public static class Tag {
public static final String endpoint_query =
"""
This endpoint is used to fetch all the available tags.<br/>
It also allows to restrict the results using a query object passed in the request body.<br/>
""";
public static final String endpoint_query_request_body =
"""
Let's explore the options this object gives us.
### <u>General query parameters:</u>
<ul>
<li><b>page:</b>
This is an object controlling the pagination of the results. It contains two properties.
</li>
<ul>
<li><b>offset:</b>
How many records to omit.
</li>
<li><b>size:</b>
How many records to include in each page.
</li>
</ul>
</ul>
For example, if we want the third page, and our pages to contain 15 elements, we would pass the following object:
```JSON
{
"offset": 30,
"size": 15
}
```
<ul>
<li><b>order:</b>
This is an object controlling the ordering of the results.
It contains a list of strings called <i>items</i> with the names of the properties to use.
<br/>If the name of the property is prefixed with a <b>'-'</b>, the ordering direction is <b>DESC</b>. Otherwise, it is <b>ASC</b>.
</li>
</ul>
For example, if we wanted to order based on the field 'createdAt' in descending order, we would pass the following object:
```JSON
{
"items": [
"-createdAt"
],
}
```
<ul>
<li><b>metadata:</b>
This is an object containing metadata for the request. There is only one available option.
<ul>
<li><b>countAll:</b>
If this is set to true, the count property included in the response will account for all the records regardless the pagination,
with all the rest of filtering options applied of course.
Otherwise, if it is set to false or not present, only the returned results will be counted.
<br/>The first option is useful for the UI clients to calculate how many result pages are available.
</li>
</ul>
</li>
<li><b>project:</b>
This is an object controlling the data projection of the results.
It contains a list of strings called <i>fields</i> with the names of the properties to project.
<br/>You can also include properties that are deeper in the object tree by prefixing them with dots.
</li>
</ul>
### <u>Tag specific query parameters:</u>
<ul>
<li><b>like:</b>
If there is a like parameter present in the query, only the tag entities that include the contents of the parameter in their labels will be in the response.
</li>
<li><b>ids:</b>
This is a list and contains the ids we want to include in the response. <br/>If empty, every record is included.
</li>
<li><b>excludedIds:</b>
This is a list and contains the ids we want to exclude from the response. <br/>If empty, no record gets excluded.
</li>
<li><b>createdByIds:</b>
This is a list and contains the ids of the users who's tags we want to exclude from the response. <br/>If empty, every record is included.
</li>
<li><b>isActive:</b>
This is a list and determines which records we want to include in the response, based on if they are deleted or not.
This filter works like this. If we want to view only the active records we pass [1] and for only the deleted records we pass [0].
<br/>If not present or if we pass [0,1], every record is included.
</li>
<li><b>tags:</b>
This is a list and determines which records we want to include in the response, based on their tag string.
<br/>If not present, every record is included.
</li>
<li><b>excludedTags:</b>
This is a list and determines which records we want to exclude from the response, based on their tag string.
<br/>If not present, no record is excluded.
</li>
</ul>
""";
public static final String endpoint_query_request_body_example =
"""
{
"project":{
"fields":[
"id",
"label",
"createdAt",
"updatedAt",
"isActive",
"belongsToCurrentTenant"
]
},
"metadata":{
"countAll":true
},
"page":{
"offset":0,
"size":10
},
"isActive":[
1
],
"order":{
"items":[
"-createdAt"
]
}
}
""";
public static final String endpoint_query_response_example =
"""
{
"items":[
{
"id":"abd9d15e-4c70-4700-bce8-e90b8d99ecd5",
"label":"PCM",
"createdAt":"2024-06-27T13:52:48.417255Z",
"updatedAt":"2024-06-27T13:52:48.417255Z",
"isActive":1,
"belongsToCurrentTenant":true
},
{
"id":"de185ef7-8d9a-458e-9af6-c7c1c9ea39e0",
"label":"Phase change material",
"createdAt":"2024-06-27T13:52:48.417255Z",
"updatedAt":"2024-06-27T13:52:48.417255Z",
"isActive":1,
"belongsToCurrentTenant":true
},
{
"id":"7b74fc3e-b283-4203-8b2c-2b9999b96ce7",
"label":"heat transfer enhancement in PCM",
"createdAt":"2024-06-27T13:52:48.417255Z",
"updatedAt":"2024-06-27T13:52:48.417255Z",
"isActive":1,
"belongsToCurrentTenant":true
},
{
"id":"d5cd61ff-26c8-4abb-a605-9400c8e6f453",
"label":"energy",
"createdAt":"2024-06-27T13:52:48.328879Z",
"updatedAt":"2024-06-27T13:52:48.328879Z",
"isActive":1,
"belongsToCurrentTenant":true
},
{
"id":"a8ab80af-dcf4-4221-85d6-3c9ef304f52d",
"label":" indicators",
"createdAt":"2024-06-27T13:52:48.328879Z",
"updatedAt":"2024-06-27T13:52:48.328879Z",
"isActive":1,
"belongsToCurrentTenant":true
},
{
"id":"b27cf507-296a-407e-87f2-e6245d60a622",
"label":"district heating",
"createdAt":"2024-06-27T13:52:48.328879Z",
"updatedAt":"2024-06-27T13:52:48.328879Z",
"isActive":1,
"belongsToCurrentTenant":true
},
{
"id":"40eea91d-e3ef-4284-8a70-76cfb544e71b",
"label":" energy resilience",
"createdAt":"2024-06-27T13:52:48.328879Z",
"updatedAt":"2024-06-27T13:52:48.328879Z",
"isActive":1,
"belongsToCurrentTenant":true
},
{
"id":"aa955ed9-7d40-486b-aec3-05515be36297",
"label":"biomass",
"createdAt":"2024-06-27T13:52:48.169676Z",
"updatedAt":"2024-06-27T13:52:48.169676Z",
"isActive":1,
"belongsToCurrentTenant":true
},
{
"id":"a777b696-f861-4eba-8bb0-60951cf3cc8f",
"label":"laboratory",
"createdAt":"2024-06-27T13:52:48.169676Z",
"updatedAt":"2024-06-27T13:52:48.169676Z",
"isActive":1,
"belongsToCurrentTenant":true
},
{
"id":"03ed72bc-af6e-47ea-b775-90674f50bdc2",
"label":"pellets",
"createdAt":"2024-06-27T13:52:48.169676Z",
"updatedAt":"2024-06-27T13:52:48.169676Z",
"isActive":1,
"belongsToCurrentTenant":true
}
],
"count":2789
}
""";
}
} }

View File

@ -11,7 +11,7 @@ springdoc:
displayName: Current displayName: Current
packagesToScan: org.opencdmp.controllers packagesToScan: org.opencdmp.controllers
packagesToExclude: org.opencdmp.controllers.publicapi packagesToExclude: org.opencdmp.controllers.publicapi
pathsToMatch: "/api/dmp/**, /api/description/**, /api/description-template/**, /api/description-template-type/**, /api/dmp-blueprint/**, /api/entity-doi/**, /api/deposit/**, /api/file-transformer/**" pathsToMatch: "/api/dmp/**, /api/description/**, /api/description-template/**, /api/description-template-type/**, /api/dmp-blueprint/**, /api/entity-doi/**, /api/deposit/**, /api/file-transformer/**, /api/tag/**"
swaggerUi: swaggerUi:
enabled: true enabled: true
useRootPath: true useRootPath: true