diff --git a/CHANGELOG.md b/CHANGELOG.md index 3924cb1b1..0717cbea6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixes `Enum` deserialization when the value is `UNSET`. - Add handling of application/vnd.api+json media type. - Support passing models into query parameters (#316). Thanks @forest-benchling! +- Add support for cookie parameters (#326). ### Changes diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/token_with_cookie_auth_token_with_cookie_get.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/token_with_cookie_auth_token_with_cookie_get.py new file mode 100644 index 000000000..a2df2a983 --- /dev/null +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/token_with_cookie_auth_token_with_cookie_get.py @@ -0,0 +1,42 @@ +from typing import Optional + +import httpx + +from ...types import Response + +Client = httpx.Client + + +def _parse_response(*, response: httpx.Response) -> Optional[Union[None, None]]: + if response.status_code == 200: + response_200 = None + + return response_200 + if response.status_code == 401: + response_401 = None + + return response_401 + return None + + +def _build_response(*, response: httpx.Response) -> Response[Union[None, None]]: + return Response( + status_code=response.status_code, + content=response.content, + headers=response.headers, + parsed=_parse_response(response=response), + ) + + +def httpx_request( + *, + client: Client, + my_token: str, +) -> Response[Union[None, None]]: + + response = client.request( + "get", + "/auth/token_with_cookie", + ) + + return _build_response(response=response) diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py index 5f5f5dac6..13080dc97 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py @@ -30,6 +30,7 @@ def _get_kwargs( url = "{}/tests/defaults".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() json_datetime_prop: Union[Unset, str] = UNSET if not isinstance(datetime_prop, Unset): @@ -94,7 +95,7 @@ def _get_kwargs( return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), "params": params, } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_booleans.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_booleans.py index eeedd5337..d025860ec 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_booleans.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_booleans.py @@ -13,11 +13,12 @@ def _get_kwargs( url = "{}/tests/basic_lists/booleans".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_floats.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_floats.py index 84735b823..e2199a3b9 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_floats.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_floats.py @@ -13,11 +13,12 @@ def _get_kwargs( url = "{}/tests/basic_lists/floats".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_integers.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_integers.py index 56197de7c..dc3c6af6a 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_integers.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_integers.py @@ -13,11 +13,12 @@ def _get_kwargs( url = "{}/tests/basic_lists/integers".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_strings.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_strings.py index d75f452fb..150ab9a22 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_strings.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_basic_list_of_strings.py @@ -13,11 +13,12 @@ def _get_kwargs( url = "{}/tests/basic_lists/strings".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py index 1ae8b4c16..ec2216810 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py @@ -19,6 +19,7 @@ def _get_kwargs( url = "{}/tests/".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() json_an_enum_value = [] for an_enum_value_item_data in an_enum_value: @@ -40,7 +41,7 @@ def _get_kwargs( return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), "params": params, } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py index 7472d8ee5..7d14632c4 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py @@ -16,6 +16,7 @@ def _get_kwargs( url = "{}/tests/int_enum".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() json_int_enum = int_enum.value @@ -27,7 +28,7 @@ def _get_kwargs( return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), "params": params, } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py index 408f2dab1..074ab9d89 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py @@ -16,13 +16,14 @@ def _get_kwargs( url = "{}/tests/json_body".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() json_json_body = json_body.to_dict() return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), "json": json_json_body, } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/no_response_tests_no_response_get.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/no_response_tests_no_response_get.py index 0f27db9f3..f1e02671d 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/no_response_tests_no_response_get.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/no_response_tests_no_response_get.py @@ -13,11 +13,12 @@ def _get_kwargs( url = "{}/tests/no_response".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_get.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_get.py index 753b64a13..b1e3a0cf7 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_get.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_get.py @@ -14,11 +14,12 @@ def _get_kwargs( url = "{}/tests/octet_stream".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py index 3de18244f..f974c9c07 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py @@ -15,6 +15,7 @@ def _get_kwargs( url = "{}/tests/optional_query_param/".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() json_query_param: Union[Unset, List[Any]] = UNSET if not isinstance(query_param, Unset): @@ -28,7 +29,7 @@ def _get_kwargs( return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), "params": params, } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py index 0f134aa87..8680e8ef8 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py @@ -16,13 +16,14 @@ def _get_kwargs( url = "{}/tests/inline_objects".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() json_json_body = json_body.to_dict() return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), "json": json_json_body, } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/token_with_cookie_auth_token_with_cookie_get.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/token_with_cookie_auth_token_with_cookie_get.py new file mode 100644 index 000000000..c497a0b3a --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/token_with_cookie_auth_token_with_cookie_get.py @@ -0,0 +1,108 @@ +from typing import Any, Dict, Optional, Union + +import httpx + +from ...client import Client +from ...types import Response + + +def _get_kwargs( + *, + client: Client, + my_token: str, +) -> Dict[str, Any]: + url = "{}/auth/token_with_cookie".format(client.base_url) + + headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() + + cookies["MyToken"] = my_token + + return { + "url": url, + "headers": headers, + "cookies": cookies, + "timeout": client.get_timeout(), + } + + +def _parse_response(*, response: httpx.Response) -> Optional[Union[None, None]]: + if response.status_code == 200: + response_200 = None + + return response_200 + if response.status_code == 401: + response_401 = None + + return response_401 + return None + + +def _build_response(*, response: httpx.Response) -> Response[Union[None, None]]: + return Response( + status_code=response.status_code, + content=response.content, + headers=response.headers, + parsed=_parse_response(response=response), + ) + + +def sync_detailed( + *, + client: Client, + my_token: str, +) -> Response[Union[None, None]]: + kwargs = _get_kwargs( + client=client, + my_token=my_token, + ) + + response = httpx.get( + **kwargs, + ) + + return _build_response(response=response) + + +def sync( + *, + client: Client, + my_token: str, +) -> Optional[Union[None, None]]: + """ Test optional cookie parameters """ + + return sync_detailed( + client=client, + my_token=my_token, + ).parsed + + +async def asyncio_detailed( + *, + client: Client, + my_token: str, +) -> Response[Union[None, None]]: + kwargs = _get_kwargs( + client=client, + my_token=my_token, + ) + + async with httpx.AsyncClient() as _client: + response = await _client.get(**kwargs) + + return _build_response(response=response) + + +async def asyncio( + *, + client: Client, + my_token: str, +) -> Optional[Union[None, None]]: + """ Test optional cookie parameters """ + + return ( + await asyncio_detailed( + client=client, + my_token=my_token, + ) + ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/unsupported_content_tests_unsupported_content_get.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/unsupported_content_tests_unsupported_content_get.py index 45dc0e5dc..a1d5d5a0d 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/unsupported_content_tests_unsupported_content_get.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/unsupported_content_tests_unsupported_content_get.py @@ -13,11 +13,12 @@ def _get_kwargs( url = "{}/tests/unsupported_content".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), } diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py index f8a54ec77..2ef1278bc 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py @@ -17,6 +17,7 @@ def _get_kwargs( url = "{}/tests/upload".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() if keep_alive is not UNSET: headers["keep-alive"] = keep_alive @@ -24,7 +25,7 @@ def _get_kwargs( return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), "files": multipart_data.to_dict(), } diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index 44e12f171..fcd83e460 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -632,6 +632,40 @@ } } } + }, + "/auth/token_with_cookie": { + "get": { + "tags": [ + "tests" + ], + "summary": "TOKEN_WITH_COOKIE", + "description": "Test optional cookie parameters", + "operationId": "token_with_cookie_auth_token_with_cookie_get", + "parameters": [ + { + "required": true, + "schema": { + "title": "Token", + "type": "string" + }, + "name": "MyToken", + "in": "cookie" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } } }, "components": { diff --git a/openapi_python_client/parser/openapi.py b/openapi_python_client/parser/openapi.py index 65acceb24..2361c3c66 100644 --- a/openapi_python_client/parser/openapi.py +++ b/openapi_python_client/parser/openapi.py @@ -19,6 +19,7 @@ class ParameterLocation(str, Enum): QUERY = "query" PATH = "path" HEADER = "header" + COOKIE = "cookie" def import_string_from_reference(reference: Reference, prefix: str = "") -> str: @@ -93,6 +94,7 @@ class Endpoint: query_parameters: List[Property] = field(default_factory=list) path_parameters: List[Property] = field(default_factory=list) header_parameters: List[Property] = field(default_factory=list) + cookie_parameters: List[Property] = field(default_factory=list) responses: List[Response] = field(default_factory=list) form_body_reference: Optional[Reference] = None json_body: Optional[Property] = None @@ -229,6 +231,8 @@ def _add_parameters( endpoint.path_parameters.append(prop) elif param.param_in == ParameterLocation.HEADER: endpoint.header_parameters.append(prop) + elif param.param_in == ParameterLocation.COOKIE: + endpoint.cookie_parameters.append(prop) else: return ParseError(data=param, detail="Parameter must be declared in path or query"), schemas return endpoint, schemas diff --git a/openapi_python_client/templates/endpoint_macros.py.jinja b/openapi_python_client/templates/endpoint_macros.py.jinja index 113c410e2..705985aab 100644 --- a/openapi_python_client/templates/endpoint_macros.py.jinja +++ b/openapi_python_client/templates/endpoint_macros.py.jinja @@ -11,6 +11,20 @@ if {{ parameter.python_name }} is not UNSET: {% endif %} {% endmacro %} +{% macro cookie_params(endpoint) %} +{% if endpoint.cookie_parameters %} + {% for parameter in endpoint.cookie_parameters %} + {% if parameter.required %} +cookies["{{ parameter.name}}"] = {{ parameter.python_name }} + {% else %} +if {{ parameter.python_name }} is not UNSET: + cookies["{{ parameter.name}}"] = {{ parameter.python_name }} + {% endif %} + {% endfor %} +{% endif %} +{% endmacro %} + + {% macro query_params(endpoint) %} {% if endpoint.query_parameters %} {% for property in endpoint.query_parameters %} @@ -103,6 +117,10 @@ json_body: {{ endpoint.json_body.get_type_string() }}, {% for parameter in endpoint.header_parameters %} {{ parameter.to_string() }}, {% endfor %} +{# cookie parameters #} +{% for parameter in endpoint.cookie_parameters %} +{{ parameter.to_string() }}, +{% endfor %} {% endmacro %} {# Just lists all kwargs to endpoints as name=name for passing to other functions #} @@ -126,4 +144,7 @@ json_body=json_body, {% for parameter in endpoint.header_parameters %} {{ parameter.python_name }}={{ parameter.python_name }}, {% endfor %} +{% for parameter in endpoint.cookie_parameters %} +{{ parameter.python_name }}={{ parameter.python_name }}, +{% endfor %} {% endmacro %} diff --git a/openapi_python_client/templates/endpoint_module.py.jinja b/openapi_python_client/templates/endpoint_module.py.jinja index 7d74cdb80..bd738073e 100644 --- a/openapi_python_client/templates/endpoint_module.py.jinja +++ b/openapi_python_client/templates/endpoint_module.py.jinja @@ -10,7 +10,7 @@ from ...types import Response, UNSET {{ relative }} {% endfor %} -{% from "endpoint_macros.py.jinja" import header_params, query_params, json_body, return_type, arguments, client, kwargs, parse_response %} +{% from "endpoint_macros.py.jinja" import header_params, cookie_params, query_params, json_body, return_type, arguments, client, kwargs, parse_response %} {% set return_string = return_type(endpoint) %} {% set parsed_responses = (endpoint.responses | length > 0) and return_string != "None" %} @@ -26,9 +26,12 @@ def _get_kwargs( ) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() {{ header_params(endpoint) | indent(4) }} + {{ cookie_params(endpoint) | indent(4) }} + {{ query_params(endpoint) | indent(4) }} {{ json_body(endpoint) | indent(4) }} @@ -36,7 +39,7 @@ def _get_kwargs( return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), {% if endpoint.form_body_reference %} "data": asdict(form_data), diff --git a/tests/test_parser/test_openapi.py b/tests/test_parser/test_openapi.py index 1336c6c39..1bbaa3e6e 100644 --- a/tests/test_parser/test_openapi.py +++ b/tests/test_parser/test_openapi.py @@ -473,7 +473,9 @@ def test__add_parameters_fail_loudly_when_location_not_supported(self, mocker): ) parsed_schemas = mocker.MagicMock() mocker.patch(f"{MODULE_NAME}.property_from_data", return_value=(mocker.MagicMock(), parsed_schemas)) - param = oai.Parameter.construct(name="test", required=True, param_schema=mocker.MagicMock(), param_in="cookie") + param = oai.Parameter.construct( + name="test", required=True, param_schema=mocker.MagicMock(), param_in="error_location" + ) schemas = Schemas() result = Endpoint._add_parameters( diff --git a/tests/test_templates/endpoint_module.py b/tests/test_templates/endpoint_module.py index c08fe74e9..d0b6a9b03 100644 --- a/tests/test_templates/endpoint_module.py +++ b/tests/test_templates/endpoint_module.py @@ -20,11 +20,12 @@ def _get_kwargs( url = "{}/post/".format(client.base_url) headers: Dict[str, Any] = client.get_headers() + cookies: Dict[str, Any] = client.get_cookies() return { "url": url, "headers": headers, - "cookies": client.get_cookies(), + "cookies": cookies, "timeout": client.get_timeout(), "data": asdict(form_data), "files": multipart_data.to_dict(),