openapi-generator
openapi-generator copied to clipboard
[BUG][Java] Content-Type input header not honored
Description
We have a REST endpoint where users can upload files of various content types. The user supplies the content type in the header. This supplied header value is not being passed correctly through the generated code (opting to set it to application/json instead).
openapi-generator version
java -jar openapi-generator-cli.jar version 4.0.1
We are creating Python clients with an advanced form of the following spec (which demonstrates the issue):
OpenAPI declaration file content or url
Open API spec (json):
{
"openapi": "3.0.1",
"info": {
"title": "Object",
"version": "2019-06-11T02:09:00.000Z"
},
"servers": [
{
"url": "https://me.com/objects/v1"
}
],
"paths": {
"/": {
"put": {
"description": "CreateObject: Creates an object within the collection specified; object-id is returned in response",
"parameters": [
{
"name": "Content-Type",
"in": "header",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"application/xml": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"image/png": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"application/octet-stream": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"application/pdf": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"image/jpeg": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"application/atom+xml": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"image/bmp": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"image/gif": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"application/xhtml+xml": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"application/rtf": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"text/html": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"image/tiff": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"text/csv": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"application/zip": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"application/vnd.ms-excel": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
},
"text/plain": {
"schema": {
"$ref": "#/components/schemas/ObjectRequest"
}
}
},
"required": true
},
"responses": {
"202": {
"description": "202 response",
"headers": {
"Access-Control-Allow-Origin": {
"schema": {
"type": "string"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ObjectResponse"
}
}
}
},
"400": {
"description": "400 response",
"headers": {
"Access-Control-Allow-Origin": {
"schema": {
"type": "string"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "403 response",
"headers": {
"Access-Control-Allow-Origin": {
"schema": {
"type": "string"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "404 response",
"headers": {
"Access-Control-Allow-Origin": {
"schema": {
"type": "string"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"405": {
"description": "405 response",
"headers": {
"Access-Control-Allow-Origin": {
"schema": {
"type": "string"
}
},
"Allow": {
"schema": {
"type": "string"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "409 response",
"headers": {
"Access-Control-Allow-Origin": {
"schema": {
"type": "string"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"422": {
"description": "422 response",
"headers": {
"Access-Control-Allow-Origin": {
"schema": {
"type": "string"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "500 response",
"headers": {
"Access-Control-Allow-Origin": {
"schema": {
"type": "string"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"security": [
{
"api_key": []
}
]
}
}
},
"components": {
"schemas": {
"Error": {
"title": "Error Response schema",
"required": [
"context",
"error"
],
"type": "object",
"properties": {
"context": {
"$ref": "#/components/schemas/ContextProperties"
},
"error": {
"$ref": "#/components/schemas/ErrorProperties"
}
}
},
"ErrorProperties": {
"title": "Error properties schema",
"required": [
"message",
"type"
],
"type": "object",
"properties": {
"stack-trace": {
"type": "array",
"items": {
"type": "string"
}
},
"corrective-action": {
"type": "string"
},
"message": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"ObjectProperties": {
"title": "Object properties schema",
"required": [
"asset-id",
"collection-id",
"collection-url",
"object-id",
"object-state",
"object-url",
"owner-id"
],
"type": "object",
"properties": {
"object-expiration-date": {
"type": "string"
},
"object-state": {
"type": "string",
"enum": [
"Created",
"Pending",
"Failed",
"Removed"
]
},
"object-url": {
"type": "string"
},
"owner-id": {
"type": "integer"
},
"collection-id": {
"type": "string"
},
"collection-url": {
"type": "string"
},
"asset-id": {
"type": "integer"
},
"object-id": {
"type": "string"
}
}
},
"ObjectRequest": {
"title": "Object body schema",
"type": "string",
"format": "binary"
},
"ObjectResponse": {
"title": "Object response schema",
"required": [
"context",
"object"
],
"type": "object",
"properties": {
"object": {
"$ref": "#/components/schemas/ObjectProperties"
}
}
}
},
"securitySchemes": {
"api_key": {
"type": "apiKey",
"name": "x-api-key",
"in": "header"
}
}
}
}
Command line used for generation
java -jar openapi-generator-cli.jar generate -i content-type-bug.json -g python -o client\object --package-name content_type_bug
Steps to reproduce
The generated code creates the following (snippit) in default_api.py, which shows that the Content-Type header is set correctly but then (almost immediately) overwritten by the result of self.api_client.select_header_content_type().
def root_put_with_http_info(self, content_type, body, **kwargs): # noqa: E501
"""root_put # noqa: E501
CreateObject: Creates an object within the collection specified; object-id is returned in response # noqa: E501
This method makes a synchronous HTTP request by default. To make an
asynchronous HTTP request, please pass async_req=True
>>> thread = api.root_put_with_http_info(content_type, body, async_req=True)
>>> result = thread.get()
:param async_req bool: execute request asynchronously
:param str content_type: (required)
:param file body: (required)
:param _return_http_data_only: response data without head status code
and headers
:param _preload_content: if False, the urllib3.HTTPResponse object will
be returned without reading/decoding response
data. Default is True.
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
:return: tuple(ObjectResponse, status_code(int), headers(HTTPHeaderDict))
If the method is called asynchronously,
returns the request thread.
"""
local_var_params = locals()
all_params = ['content_type', 'body'] # noqa: E501
all_params.append('async_req')
all_params.append('_return_http_data_only')
all_params.append('_preload_content')
all_params.append('_request_timeout')
for key, val in six.iteritems(local_var_params['kwargs']):
if key not in all_params:
raise ApiTypeError(
"Got an unexpected keyword argument '%s'"
" to method root_put" % key
)
local_var_params[key] = val
del local_var_params['kwargs']
# verify the required parameter 'content_type' is set
if ('content_type' not in local_var_params or
local_var_params['content_type'] is None):
raise ApiValueError("Missing the required parameter `content_type` when calling `root_put`") # noqa: E501
# verify the required parameter 'body' is set
if ('body' not in local_var_params or
local_var_params['body'] is None):
raise ApiValueError("Missing the required parameter `body` when calling `root_put`") # noqa: E501
collection_formats = {}
path_params = {}
query_params = []
header_params = {}
if 'content_type' in local_var_params:
header_params['Content-Type'] = local_var_params['content_type'] # noqa: E501
form_params = []
local_var_files = {}
body_params = None
if 'body' in local_var_params:
body_params = local_var_params['body']
# HTTP header `Accept`
header_params['Accept'] = self.api_client.select_header_accept(
['application/json']) # noqa: E501
# HTTP header `Content-Type`
header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501
['application/json', 'application/xml', 'image/png', 'application/octet-stream', 'application/pdf', 'image/jpeg', 'application/atom+xml', 'image/bmp', 'image/gif', 'application/xhtml+xml', 'application/rtf', 'text/html', 'image/tiff', 'text/csv', 'application/zip', 'application/vnd.ms-excel', 'text/plain']) # noqa: E501
# Authentication setting
auth_settings = ['api_key'] # noqa: E501
return self.api_client.call_api(
'/', 'PUT',
path_params,
query_params,
header_params,
body=body_params,
post_params=form_params,
files=local_var_files,
response_type='ObjectResponse', # noqa: E501
auth_settings=auth_settings,
async_req=local_var_params.get('async_req'),
_return_http_data_only=local_var_params.get('_return_http_data_only'), # noqa: E501
_preload_content=local_var_params.get('_preload_content', True),
_request_timeout=local_var_params.get('_request_timeout'),
collection_formats=collection_formats)
Suggest a fix
The call to self.api_client.select_header_content_type() should only be made if the Content-Type header hasn't already been set.
👍 Thanks for opening this issue! 🏷 I have applied any labels matching special text in your issue.
The team will review the labels and make any necessary changes.
Hello, just wanted to follow up on this issue - We experienced the same problem with our python client. it sets Application/json as the default header for all requests, including ones that doesn't have a body (GET and DELETE etc) which causes our server to reject the requests due to validation errors.
Update: This problem exists in the Java generated code as well. This isn't a Python-only issue.
Is this problem going on? It's a problem that Application/json set in the header
This has been fixed in python-experimental. One can see two content-types defined for the request body here: https://github.com/OpenAPITools/openapi-generator/blob/master/samples/openapi3/client/petstore/python-experimental/petstore_api/api/fake_api_endpoints/inline_composition.py#L331 And then the developer must input their used content_type and it will be used when serializing the data in the request body here: https://github.com/OpenAPITools/openapi-generator/blob/master/samples/openapi3/client/petstore/python-experimental/petstore_api/api/fake_api_endpoints/inline_composition.py#L529
I am removing the [Python] tag from this issue because we have the above python-experimental generator which support this use case