Refactored swagger docs contents to reflect better the relevant parts of the docs, added query examples for dmp and description queries.

This commit is contained in:
Thomas Georgios Giannos 2024-06-03 15:58:46 +03:00
parent 601b748388
commit 8e2dcc855a
2 changed files with 283 additions and 16 deletions

View File

@ -13,6 +13,9 @@ import gr.cite.tools.logging.MapLogEntry;
import gr.cite.tools.validation.ValidationFilterAnnotation;
import io.swagger.v3.oas.annotations.Hidden;
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.tags.Tag;
import jakarta.xml.bind.JAXBException;
import org.opencdmp.audit.AuditableAction;
@ -146,7 +149,24 @@ public class DescriptionController {
}
@PostMapping("query")
@Operation(summary = "Query all descriptions", description = SwaggerHelpers.endpoint_query)
@Operation(
summary = "Query all descriptions",
description = SwaggerHelpers.endpoint_query,
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = SwaggerHelpers.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.endpoint_query_request_body_example
)
}
)
}
)
)
public QueryResult<Description> query(@RequestBody DescriptionLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", Description.class.getSimpleName());
@ -162,7 +182,10 @@ public class DescriptionController {
@GetMapping("{id}")
@Operation(summary = "Fetch a specific description by id")
public Description get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
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 = "This is an object containing a list of the properties you wish to include in the response, similar to the 'project' attribute on queries.", required = true) FieldSet fieldSet)
throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving" + Description.class.getSimpleName()).And("id", id).And("fields", fieldSet));
fieldSet = this.fieldSetExpanderService.expand(fieldSet);
@ -342,6 +365,10 @@ public class DescriptionController {
"""
This endpoint is used to fetch all the available descriptions.<br/>
It also allows to restrict the results using a query object passed in the request body.<br/>
""";
static final String endpoint_query_request_body =
"""
Let's explore the options this object gives us.
### <u>General query parameters:</u>
@ -451,7 +478,60 @@ public class DescriptionController {
</ul>
""";
static final String endpoint_ =
static final String endpoint_query_request_body_example =
"""
{
"project":{
"fields":[
"id",
"label",
"status",
"updatedAt",
"belongsToCurrentTenant",
"finalizedAt",
"descriptionTemplate.id",
"descriptionTemplate.label",
"descriptionTemplate.groupId",
"dmp.id",
"dmp.label",
"dmp.status",
"dmp.accessType",
"dmp.blueprint.id",
"dmp.blueprint.label",
"dmp.blueprint.definition.sections.id",
"dmp.blueprint.definition.sections.label",
"dmp.blueprint.definition.sections.hasTemplates",
"dmp.dmpReferences.id",
"dmp.dmpReferences.reference.id",
"dmp.dmpReferences.reference.label",
"dmp.dmpReferences.reference.type.id",
"dmp.dmpReferences.reference.reference",
"dmp.dmpReferences.isActive",
"dmpDescriptionTemplate.id",
"dmpDescriptionTemplate.dmp.id",
"dmpDescriptionTemplate.descriptionTemplateGroupId",
"dmpDescriptionTemplate.sectionId"
]
},
"page":{
"size":5,
"offset":0
},
"order":{
"items":[
"-updatedAt"
]
},
"metadata":{
"countAll":true
},
"isActive":[
1
]
}
""";
static final String endpoint_get =
"""
""";

View File

@ -12,6 +12,8 @@ import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry;
import gr.cite.tools.validation.ValidationFilterAnnotation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.xml.bind.JAXBException;
import org.opencdmp.audit.AuditableAction;
@ -75,16 +77,16 @@ public class DmpController {
private final QueryFactory queryFactory;
private final MessageSource messageSource;
private final ElasticQueryHelperService elasticQueryHelperService;
public DmpController(
BuilderFactory builderFactory,
AuditService auditService,
DmpService dmpService,
CensorFactory censorFactory,
QueryFactory queryFactory,
MessageSource messageSource,
BuilderFactory builderFactory,
AuditService auditService,
DmpService dmpService,
CensorFactory censorFactory,
QueryFactory queryFactory,
MessageSource messageSource,
ElasticQueryHelperService elasticQueryHelperService) {
this.builderFactory = builderFactory;
this.auditService = auditService;
@ -92,9 +94,9 @@ public class DmpController {
this.censorFactory = censorFactory;
this.queryFactory = queryFactory;
this.messageSource = messageSource;
this.elasticQueryHelperService = elasticQueryHelperService;
}
this.elasticQueryHelperService = elasticQueryHelperService;
}
@PostMapping("public/query")
@Operation(summary = "Query public published plans")
public QueryResult<PublicDmp> publicQuery(@RequestBody DmpLookup lookup) throws MyApplicationException, MyForbiddenException {
@ -117,10 +119,11 @@ public class DmpController {
this.censorFactory.censor(PublicDmpCensor.class).censor(fieldSet);
DmpQuery query = this.queryFactory.query(DmpQuery.class).disableTracking().authorize(EnumSet.of(Public)).ids(id).isActive(IsActive.Active).statuses(DmpStatus.Finalized).accessTypes(DmpAccessType.Public);
DmpQuery query = this.queryFactory.query(DmpQuery.class).disableTracking().authorize(EnumSet.of(Public)).ids(id).isActive(IsActive.Active).statuses(DmpStatus.Finalized).accessTypes(DmpAccessType.Public);
PublicDmp model = this.builderFactory.builder(PublicDmpBuilder.class).authorize(EnumSet.of(Public)).build(fieldSet, query.firstAs(fieldSet));
if (model == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale()));
if (model == null)
throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale()));
this.auditService.track(AuditableAction.Dmp_PublicLookup, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("id", id),
@ -131,7 +134,24 @@ public class DmpController {
}
@PostMapping("query")
@Operation(summary = "Query all plans")
@Operation(
summary = "Query all plans",
description = SwaggerHelpers.endpoint_query,
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = SwaggerHelpers.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.endpoint_query_request_body_example
)
}
)
}
)
)
public QueryResult<Dmp> Query(@RequestBody DmpLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", Dmp.class.getSimpleName());
@ -401,4 +421,171 @@ public class DmpController {
return model;
}
protected static class SwaggerHelpers {
static final String endpoint_query =
"""
This endpoint is used to fetch all the available plans.<br/>
It also allows to restrict the results using a query object passed in the request body.<br/>
""";
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>Plan specific query parameters:</u>
<ul>
<li><b>like:</b>
If there is a like parameter present in the query, only the description entities that include the contents of the parameter either in their labels or the descriptions 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>groupIds:</b>
This is a list and contains the group ids we want the plans to have. Every plan and all its versions, have the same groupId. <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>statuses:</b>
This is a list and determines which records we want to include in the response, based on their status.
The status can be <i>Draft</i> or <i>Finalized</i>. We add 0 or 1 to the list respectively.
<br/>If not present, every record is included.
</li>
<li><b>versionStatuses:</b>
This is a list and determines which records we want to include in the response, based on their version status.
The status can be <i>Current</i>, <i>Previous</i> or <i>NotFinalized</i>. We add 0, 1 or 2 to the list respectively.
<br/>If not present, every record is included.
</li>
<li><b>accessTypes:</b>
This is a list and determines which records we want to include in the response, based on their access type.
The access type can be <i>Public</i> or <i>Restricted</i>. We add 0 or 1 to the list respectively.
<br/>If not present, every record is included.
</li>
</ul>
""";
static final String endpoint_query_request_body_example =
"""
{
"project":{
"fields":[
"id",
"label",
"description",
"status",
"accessType",
"version",
"versionStatus",
"groupId",
"updatedAt",
"belongsToCurrentTenant",
"finalizedAt",
"hash",
"descriptions.id",
"descriptions.label",
"descriptions.status",
"descriptions.descriptionTemplate.groupId",
"descriptions.isActive",
"blueprint.id",
"blueprint.label",
"blueprint.definition.sections.id"
]
},
"page":{
"size":5,
"offset":0
},
"order":{
"items":[
"-updatedAt"
]
},
"metadata":{
"countAll":true
},
"isActive":[
1
],
"versionStatuses":[
0,
2
]
}
""";
static final String endpoint_ =
"""
""";
}
}