Springfox to OpenAPI Springdocs migration: #ApiImplicitParam(allowMultiple=true) equivalent? - spring-boot

I'm migrating from springfox to OpenAPI springdocs and I have to replace
#ApiImplicitParam(allowMultiple=true)
#ApiImplicitParam is replaced with #Parameter, but what is the OpenAPI springdoc equivalent to allowMultiple=true?
Reference: https://springdoc.org/migrating-from-springfox.html

You can use the below approach
Before
#ApiImplicitParam(value="Filter by type", allowableValues="typeA,typeB,typeC",
allowMultiple=false)
After
#Parameter(description = "Filter by type",
schema=#Schema(type="string",
allowableValues={"typeA","typeB","typeC"}, defaultValue = "typeA"))

This answer is taken from what #tomjankes put in his comment to the question -> the answer is to add explode=Explode.TRUE. Here's an example piece of code that worked for me:
#Parameters({
#Parameter(name = "sort", **explode = Explode.TRUE**, schema = #Schema(type = "string"), in = ParameterIn.QUERY, description = "Sort setting in the format of: property(,asc|desc). Default sort order is ascending. Multiple sort settings are supported.")
})

Related

#Value on R2dbc table fields

Given the following entity/table defined in a Spring/KotlinCoroutines project.
#Table("workers")
data class Worker(
#Id
val id: UUID? = null,
#Column(value = "photo")
var photo: String? = null,
// see: https://github.com/spring-projects/spring-data-r2dbc/issues/449
#Transient
#Value("#{root.photo!=null}")
val hasPhoto: Boolean = false
)
The hasPhoto field does not map to a table field. I follow the R2dbc official reference doc and use a Spring EL to evaluate the EL result as value of this field.
But when I test this hasPhoto, it always returns false even I set the photo to a nonnull string.
Got answer from the Spring guys, #Value here only can access the projection.

OpenApi not picking up 'example' from #Schema

In my request model, I have a field like
#NotNull
#Schema(description = "blahblah", example = "19680228", type = "Date", format = "String", pattern = "([0-9]{4})(?:[0-9]{2})([0-9]{2})", required = true, nullable = false)
#JsonDeserialize(using = CustomDateDeserializer.class)
private OffsetDateTime birthDate;
As you can see, I have example = "19680228" in #Schema.
When I go to https://editor.swagger.io/ and paste my .yaml file into it, I would expect that it would pick the example up and show the birthDate in example section of my endpoint and in my model schema as 19680228. I would else expect that example was generated in yaml when I hit the /api-docs.yaml endpoint but it is not:
Here is how it shows in my model:
And here is how Example value of my controller looks:
As you can see, the format is still getting the format for OffsetDateTime and there is no example at all.
However, if I modify yaml in https://editor.swagger.io/ and add example as below:
, then my schema model shows it
, and also example in controller shows it as 19680210:
So, it looks like OpenApi is not processing #Schema properly.
i had the same problem, and i didn't find proper solution for it, the only solution was using String type with pattern.
like this
#Schema(type = "String" , example = "2022-10-10 00:00:00", pattern = "yyyy-MM-dd HH:mm:ss").

Open API 3 - How to read Spring Boot Pagination Properties?

I am using Spring Boot + Spring Rest Pagination + Open API 3.
#Operation(summary = "Find Contacts by name", description = "Name search by %name% format", tags = { "contact" })
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "successful operation", content = #Content(array = #ArraySchema(schema = #Schema(implementation = Contact.class)))) })
#Parameter(in = ParameterIn.QUERY, description = "Zero-based page index (0..N)", name = "page"
, content = #Content(schema = #Schema(type = "integer", defaultValue = "0")))
#Parameter(in = ParameterIn.QUERY, description = "The size of the page to be returned", name = "size"
, content = #Content(schema = #Schema(type = "integer", defaultValue = "20")))
#Parameter(in = ParameterIn.QUERY, description = "Sorting criteria in the format: property(,asc|desc). "
+ "Default sort order is ascending. " + "Multiple sort criteria are supported."
, name = "sort", content = #Content(array = #ArraySchema(schema = #Schema(type = "string"))))
#GetMapping(value = "/contacts")
public ResponseEntity<List<Contact>> findAll(Pagination pagination) {
List<Contact> contacts = new ArrayList<>();
contacts.add(Contact.builder().address1("Address1").address2("Address2").build());
return new ResponseEntity<>(contacts, HttpStatus.OK);
}
Since I'm using Spring Boot Application. I've configured below configurations,
# Added for Pagination
spring.data.web.pageable.default-page-size=25
spring.data.web.pageable.page-parameter=page
spring.data.web.pageable.size-parameter=size
spring.data.web.sort.sort-parameter=sort
Is there any way we can configure above properties for the Open API 3 specification instead of making it hard-coded ?
The support for Pageable of spring-data-commons is available. If only want to enable the support of spring Pageable Type, you can just enable it using:
SpringDocUtils.getConfig().replaceWithClass(org.springframework.data.domain.Pageable.class,
org.springdoc.core.converters.models.Pageable.class);
Alternately, the projects that use Pageable type can aslo add the follwing dependency together with the springdoc-openapi-ui dependency which will enable the support of spring.data.rest.default... properties and #PageableDefault annotation as well:
Note that latest.version should be at least equal to v1.4.5 which adds this new features
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-data-rest</artifactId>
<version>latest.version</version>
</dependency>
More details are available on the F.A.Q:
https://springdoc.org/faq.html#how-can-i-map-pageable-spring-date-commons-object-to-correct-url-parameter-in-swagger-ui
I've also was looking for this and discovered that SpringDoc now has an annotation to add the needed Parameters, #PageableAsQueryParam. I'm using springdoc-openapi-ui-1.6.4
Just make sure that you hide the Pageable object with #Parameter(hidden=true), as it will not be automatically hidden.
An example
#GetMapping("/customerQuery")
#PageableAsQueryParam
public List<PartyDTO> getCustomers(String name, #Parameter(hidden = true) Pageable pageable){
return partyService.queryCustomer(name, pageable).getContent();
}
will result into:
Used dependencies:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.4</version>
</dependency>

Swagger 2 UI How to show models that are not explicitly returned by RestController

I'm having following issue, on swagger under Models, i see just abstract Base class that is extended by 3 other classes. My current end point returns Base type of class, because i can have 3 different types returned on one end point.
So basically i have something like this
#MappedSuperclass
#ApiModel(description = "Base Details.")
abstract class BaseClass(
open var id: String? = null,
var prop1: String? = null,
var prop2: String? = null,
var prop3: String? = null,
var prop4: String? = null
)
#ApiModel(description = "Some Specific Details that contains all base properties.")
data class AnotherClass(
val prop4: String,
val prop5: String,
val prop6: Set<Amount>,
val prop7: Set<Amount>,
val prop8: String
) : BaseClass()
#ApiModel(description = "Some more Specific Details that contains all base properties.")
data class OneMoreClass(
val prop4: String,
val prop5: String
) : BaseClass()
And in RestController i have this
#GetMapping
#ApiOperation(value = "End point description", notes = "Notes notes notes.")
fun getSomethingFromDatabase(): List<BaseClass> {
return someService.getData();
}
So issue that i have is on swagger UI, under Models section i see just BaseClass and no other classes at all...
I tried this, because somewhere i seen this example:
#ApiModel(description = "Base Details.", subTypes = {AnotherClass.class})
BaseClass
but this way i have "kotlin" issue, that is saying "name is missing", also i can not do AnotherClass::class...
You will have to add those in the config as below:
return new Docket(DocumentationType.SWAGGER_2)
.additionalModels(typeResolver.resolve(AnotherClass.class), typeResolver.resolve(OneMoreClass.class))
.....
subTypes is still not completely supported in Swagger 2, still has an open ticket
For your Kotlin config, this is how it should look like:
subTypes = [AnotherClass::class, OneMoreClass::class]
I have just added a sample Kotlin controller for you to refer in my github project. Look for AnimalController.kt & SwaggerConfig for required setup.

Using #RequestParam annotated method with swagger ui

I am using Springfox libraries to generate documentation for REST service and display it in Swagger UI. I followed the directions in Springfox documentation.
I have one controller, which uses parameters from query string and the method is mapped as following:
#ApiOperation(value = "")
#RequestMapping(method = GET, value = "/customcollection/{id}/data")
public Iterable<CustomeType> getData(#ApiParam(value = "The identifier of the time series.")
#PathVariable String id,
#ApiParam(name = "startDate", value = "start date", defaultValue = "")
#RequestParam("startDate") String startDate,
#ApiParam(name = "endDate", value = "end date", defaultValue = "")
#RequestParam("endDate") String endDate)
The resulting mapper in swagger-ui then displayed as:
GET /customcollection/{id}/data{?startDate,endDate}
Parameters are displayed correctly in the UI:
But when I click on Try it Out, the request URL is misformed:
http://localhost:8080/customcollection/1/data{?startDate,endDate}?startDate=1&endDate=2
How can it be fixed?
This was caused by the line
enableUrlTemplating(true)
in Docket configuration which I copied from example and forgot to remove.
After removing this line everything is working as expected.

Resources