The documentation for migrating to SpringDoc from Swagger2/SpringFox does not address how to convert response and responseContainer fields on #ApiOperation to the new #Operation annotation. How do I do this?
Before converting to SpringDoc, I was using response and responseContainer in SpringFox Swagger 2 to explicitly declare, for example, response="MyResponseDto.class" and responseContainer="List" in order to ensure that all MyResponseDto's properties and containing collection(s) were properly displayed in the Responses section of the documentation for each API call rather than just "string" or "object".
SpringDoc handles this all automatically and displays the responses correctly as long as I add the proper typing to the generic for ResponseEntity on my REST controller method signature.
So instead of this:
#GetMapping(value = "/items/{id}")
#Operation(summary = "Get items for component", description = "Retrieves all items for the component by the supplied id")
public ResponseEntity updateMapItem(#PathVariable String id) {
return new ResponseEntity<>(myService.getItemsForComponent(id), HttpStatus.OK);
}
Use this:
#GetMapping(value = "/items/{id}")
#Operation(summary = "Get items for component", description = "Retrieves all items for the component by the supplied id")
public ResponseEntity<List<MyResponseDto>> updateMapItem(#PathVariable String id) {
return new ResponseEntity<>(myService.getItemsForComponent(id), HttpStatus.OK);
}
Therefore, response="" and responseContainer="" are no longer necessary.
Related
I'm returning a Page<SomeObject> In my method endpoints. In my OpenAPI UI, how can I generate a description of the fields that come from org.springframework.data.domain.Page type.
Normally what I do is go to the Object that I want to document and annotate its fields with #Schema(description = "some description"). But I don't have access to the Page class. How can I document its fields?
I'm probably missing something simple here, but any help would be appreciated.
PS: I am using OpenAPI v3 and springdoc
You can use OpenApiCustomiser.
Let's say for example you have this controller:
#RestController
public class HelloController {
#GetMapping("/hello")
Page<PersonDTO> getPage() {
return null;
}
}
Let's suppose you want add the description the Pageable element:
#Bean
public OpenApiCustomiser pageableOpenApiCustomiser() {
return openApi -> {
Schema pageableSchema = openApi.getComponents().getSchemas().get("Pageable");
pageableSchema.setDescription("my description");
};
}
The same logic applies for any other attribute you nned to customize.
I have an ODataController with a Get method as such:
public IHttpActionResult Get(ODataQueryOptions<MyModel> queryOptions) {
IQueryable<MyModel> models = _Models.AsQueryable(); // _Models Defined in Controller as List<MyModel> and is already populated with nested data for both .LevelOne and .LevelOne.LevelTwo which are two other Lists.
Uri fullrequest = Request.GetRequestContext().Url.Request.RequestUri; // http://localhost:8080/odata/Root?$expand=LevelOne($expand=LevelTwo)
Uri serviceroot = new Uri(controller.GetLeftPart(UriPartial.Path).Replace("/Root", "")); // http://localhost:8080/odata
String metadata = service + "/$metadata"; // http://localhost:8080/odata/$metadata
IEdmModel model = EdmxReader.Parse(XmlTextReader.Create(metadata));
ODataUriParser parser = new ODataUriParser(model, serviceroot, fullrequest);
SelectExpandClause selectAndExpand = parser.ParseSelectAndExpand();
//Only one of the two below lines is ever commented in...
Request.ODataProperties().SelectExpandClause = queryOptions.SelectExpand.SelectExpandClause; // This line will work
Request.ODataProperties().SelectExpandClause = selectAndExpand; // This line will not work
return Ok(models);
}
using my manually parsed selectAndExpand does not expand the dataset, but using the predefined queryOptions one does. Any ideas why? Both objects appear to contain the same information while viewed in the debugger, but I must be missing something. I want to be able to parse the URI myself, without the need for the ODataQueryOptions at all.
What I ended up doing, was building a new ODataQueryOptions object based off the original request, and then pulling just the SelectExpandClause from that. It doesn't answer my initial question, but it is a somewhat working solution for not having to pass in a ODataQueryOptions parameter. See my Code below:
public IHttpActionResult Get() {
//Get Queryable Item (in this case just a list made queryable)
IQueryable<MyModel> models = _Models.AsQueryable();
//Create new ODataQueryContext based off initial request (required to create ODataQueryOptions)
ODataQueryContext selectAndExpandContext = new ODataQueryContext(Request.ODataProperties().Model, typeof(MyModel), Request.ODataProperties().Path);
//Create new ODataQueryOptions based off new context and original request
ODataQueryOptions<Employee> selectAndExpandOptions = new ODataQueryOptions<Employee>(selectAndExpandContext, Request);
//Attach Select + Expand options to be processed
if (selectAndExpandOptions.SelectExpand != null) {
Request.ODataProperties().SelectExpandClause = selectAndExpandOptions.SelectExpand.SelectExpandClause;
}
return Ok(models);
}
I'm trying to do a straight forward data bind that involved two domain classes in a one to one association. Here's the two classes:
class Request
{
static hasOne = [form: Form]
Form form
}
class Form
{
static belongsTo = [request: Request]
String string
}
I then do the following data binding (this is to demonstrate the problem ... the real data bind comes from a form):
Request request = new Request()
request.properties = ['form.string': 'string value']
However, I end up with a Request object that has a null form property instead of a Request object that has a Form object for its form property along with the string value.
Try with this
class Request
{
Form form
}
class Form
{
static belongsTo = [request: Request]
String string
}
Turns out the problem wasn't with the actual classes, but the map being passed to the data binding. Even though according to the Grails documentation the following should have worked:
Request request = new Request()
request.properties = ['form.string': 'string value']
it doesn't. However, if I change the map to be I get proper binding:
Request request = new Request()
request.properties = [form: [string: 'string value']]
How to configure swaggerui to display correct parameter datatype for JAX-RS resources which have collection input parameters?
Below is a sample groovy JAX-RS resource. Its input is of type List<User>
#POST
#Produces(APPLICATION_JSON)
#Consumes(APPLICATION_JSON)
#ApiOperation(value = "Create(s) users", response = User, responseContainer = "List")
Response createUsers(List<User> questions) {
}
In the swagger UI, I see the List with empty type populated instead of User. It works fine for output parameters. Using ApiOperation annotation, I could specify for response type.
#ApiOperation(value = "Create(s) users", response = User, responseContainer = "List")
For input parameters, How do I see List of User model schema in the swagger UI?
Try using #ApiParam on List:
#POST
#Produces(APPLICATION_JSON)
#Consumes(APPLICATION_JSON)
#ApiOperation(value = "Create(s) users", response = User, responseContainer = "List")
Response createUsers(#ApiParam("description") List<User> questions) {
}
I am using .net MVC Web API project template. This is my Get method in customer controller:
public IQueryable<Customer> Get()
{
CustomerRepository customer = new CustomerRepository ();
IQueryable<Customer> customer = lr.GetCustomer();
return data;
}
How can I add the content range headers along with data returned?:
content-range: item 0-9/100
**EDIT
I changed it to return HttpResponseMessage but still unsure about setting the content-range item. Not sure if I hard code "item 0-9/100" or if there is mechanism to know how many items to return?
public HttpResponseMessage Get()
{
CustomerRepository lr = new CustomerRepository();
IQueryable<Customer> data = lr.GetCustomer();
var resp = new HttpResponseMessage(HttpStatusCode.OK);
resp.Content = new ObjectContent<IQueryable<Customer>>(data, new JsonMediaTypeFormatter());
resp.Headers.Add("Content-Range", ???????)
return resp;
}
Answer to edited question.
The Content range header refers an index of the results returned in the Http Response. Item 0-9/100 means the response contains the first 10 items (indexes 0,1,2,3,4,5,6,7,8,9) of the 100 total.
It would make sense to return the index that matches the results returned from your method. You will need to determine what indexes are represented in your IQueryable<Customer> customer object and fill out the header appropriately.