OpenAPITools / OpenAPITools/openapi-generator
[REQ] Media type versioning
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Problem
It is not possible to use the Accept Header in the request for versioning endpoint rest services (instead of URI Versioning).
by example, We want versioning the "findStock" method using the content-type for the same path "/stock" in this contract first:
/stock:
get:
tags:
- stock
summary: Get stock
operationId: findStock
responses:
'200':
description: A paged array of Inventory Items
content:
"application/vnd.mecstkac.v1.0.0+json":
schema:
$ref: "#/components/schemas/InventoryItemV1"
"application/vnd.mecstkac.v1.0.1+json":
schema:
$ref: "#/components/schemas/InventoryItemV2"
When we generate the code from the contract described above, it generates an API with a single "findStock" method that returns only one type of response:
@ApiResponses(value = {
@ApiResponse(code = 200, message = "A paged array of Inventory Items", response = InventoryItemV1.class) })
@RequestMapping(value = "/stock",
produces = { "application/vnd.mecstkac.v1.0.0+json", "application/vnd.mecstkac.v1.0.1+json" },
method = RequestMethod.GET)
default ResponseEntity<InventoryItemV1> findStock() {
getRequest().ifPresent(request -> {
for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf(""))) {
ApiUtil.setExampleResponse(request, "", "");
break;
}
}
});
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
Solution
Use the Accept Header in the request for versioning endpoint rest. By example, We want versioning the "findStock" method using the content-type for the same path "/stock" in this contract first:
/stock:
get:
tags:
- stock
summary: Get stock
operationId: findStock
responses:
'200':
description: A paged array of Inventory Items
content:
"application/vnd.mecstkac.v1.0.0+json":
schema:
$ref: "#/components/schemas/InventoryItemV1"
"application/vnd.mecstkac.v1.0.1+json":
schema:
$ref: "#/components/schemas/InventoryItemV2"
-> if content-type is "application/vnd.mecstkac.v1.0.0+json" return response "InventoryItemV1"
-> if content-type is "application/vnd.mecstkac.v1.0.1+json" return response "InventoryItemV2"
the self-generated code for server interface would be something like :
@GetMapping(value = "/stock", produces = "application/vnd.mecstkac.v1.0.0+json")
public ResponseEntity<InventoryItemV1> findStockV1_0_0() {
getRequest().ifPresent(request -> {
for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf(""))) {
ApiUtil.setExampleResponse(request, "", "");
break;
}
}
});
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
@GetMapping(value = "/stock", produces = "application/vnd.mecstkac.v1.0.0+json")
public ResponseEntity<InventoryItemV2> findStockV1_0_1() {
getRequest().ifPresent(request -> {
for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf(""))) {
ApiUtil.setExampleResponse(request, "", "");
break;
}
}
});
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
the self-generated code for client interface would be something like :
public InventoryItemV1 findStockV1_0_0() throws RestClientException {
Object postBody = null;
String path = UriComponentsBuilder.fromPath("/stock").build().toUriString();
final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
final HttpHeaders headerParams = new HttpHeaders();
final MultiValueMap<String, Object> formParams = new LinkedMultiValueMap<String, Object>();
final String[] accepts = { "application/vnd.mecstkac.v1.0.0+json" };
final List<MediaType> accept = apiClient.selectHeaderAccept(accepts);
final String[] contentTypes = { };
final MediaType contentType = apiClient.selectHeaderContentType(contentTypes);
String[] authNames = new String[] { };
ParameterizedTypeReference<InventoryItemV1> returnType = new ParameterizedTypeReference<InventoryItemV1>() {};
return apiClient.invokeAPI(path, HttpMethod.GET, queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType);
}
public InventoryItemV2 findStockV1_0_1() throws RestClientException {
Object postBody = null;
String path = UriComponentsBuilder.fromPath("/stock").build().toUriString();
final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
final HttpHeaders headerParams = new HttpHeaders();
final MultiValueMap<String, Object> formParams = new LinkedMultiValueMap<String, Object>();
final String[] accepts = { "application/vnd.mecstkac.v1.0.1+json" };
final List<MediaType> accept = apiClient.selectHeaderAccept(accepts);
final String[] contentTypes = { };
final MediaType contentType = apiClient.selectHeaderContentType(contentTypes);
String[] authNames = new String[] { };
ParameterizedTypeReference<InventoryItemV1> returnType = new ParameterizedTypeReference<InventoryItemV1>() {};
return apiClient.invokeAPI(path, HttpMethod.GET, queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType);
}
for both reactive and non-reactive implementation.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the Java generator entry points for Spring server and client interfaces from the OpenAPI response content definitions. Compare reactive and non-reactive generation paths, then verify that media-type versions produce distinct methods and response types for both server and client interfaces.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, openapi, spring
- Domain
- api, backend, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100