Skip to content

Support patterned and default HTTP status codes #1303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .changeset/support_patterned_and_default_http_statuses.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
default: minor
---

# Support patterned and default HTTP statuses

HTTP statuses like `2XX` and `default` are now supported!

A big thank you to:
- @PSU3D0 for PR #973 (eons ago 😅)
- @obs-gh-peterkolloch for PR #1300
- @goodsonjr for PR #1304

Closes #1271 and #832

> [!NOTE]
> Custom template users: the `endpoint.responses` type has changed quite a bit. Check out #1303 for the changes.
2 changes: 1 addition & 1 deletion end_to_end_tests/__snapshots__/test_end_to_end.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

WARNING parsing GET / within default.

Invalid response status code abcdef (not a valid HTTP status code), response will be omitted from generated client
Invalid response status code pattern: abcdef, response will be omitted from generated client


If you believe this was a mistake or this tool is missing a feature you need, please open an issue at https://github.com/openapi-generators/openapi-python-client/issues/new/choose
Expand Down
134 changes: 129 additions & 5 deletions end_to_end_tests/baseline_openapi_3.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,7 @@
"some_nullable_object",
"some_required_number"
],
"properties": {
}
"properties": {}
}
}
},
Expand Down Expand Up @@ -975,6 +974,124 @@
}
}
},
"/responses/status-codes/default": {
"get": {
"tags": [
"responses"
],
"summary": "Default Status Code Only",
"operationId": "default_status_code",
"responses": {
"default": {
"description": "Default response",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/response/status-codes/patterns": {
"get": {
"tags": [
"responses"
],
"summary": "Status Code Patterns",
"operationId": "status_code_patterns",
"responses": {
"2XX": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"success",
"failure"
]
}
}
}
}
}
},
"4XX": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
}
}
}
}
}
}
},
"/response/status-codes/precedence": {
"get": {
"operationId": "status_code_precedence",
"tags": [
"responses"
],
"summary": "Status Codes Precedence",
"description": "Verify that specific status codes are always checked first, then ranges, then default",
"responses": {
"default": {
"description": "Default Response Should Be Last",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"4XX": {
"description": "Pattern should be after specific codes",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/auth/token_with_cookie": {
"get": {
"tags": [
Expand Down Expand Up @@ -1133,7 +1250,10 @@
},
"/tag_with_number": {
"get": {
"tags": ["1", "2"],
"tags": [
"1",
"2"
],
"responses": {
"200": {
"description": "Success"
Expand Down Expand Up @@ -1668,7 +1788,9 @@
"type": "string"
}
},
"required": ["type"]
"required": [
"type"
]
},
{
"type": "object",
Expand All @@ -1680,7 +1802,9 @@
"type": "string"
}
},
"required": ["type"]
"required": [
"type"
]
}
]
}
Expand Down
109 changes: 109 additions & 0 deletions end_to_end_tests/baseline_openapi_3.1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,115 @@ info:
}
}
},
"/responses/status-codes/default": {
"get": {
"tags": ["responses"],
"summary": "Default Status Code Only",
"operationId": "default_status_code",
"responses": {
"default": {
"description": "Default response",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/response/status-codes/patterns": {
"get": {
"tags": ["responses"],
"summary": "Status Code Patterns",
"operationId": "status_code_patterns",
"responses": {
"2XX": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["success", "failure"]
}
}
}
}
}
},
"4XX": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
}
}
}
}
}
}
},
"/response/status-codes/precedence": {
"get": {
"operationId": "status_code_precedence",
"tags": ["responses"],
"summary": "Status Codes Precedence",
"description": "Verify that specific status codes are always checked first, then ranges, then default",
"responses": {
"default": {
"description": "Default Response Should Be Last",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"4XX": {
"description": "Pattern should be after specific codes",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/auth/token_with_cookie": {
"get": {
"tags": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@

import types

from . import post_responses_unions_simple_before_complex, reference_response, text_response
from . import (
default_status_code,
post_responses_unions_simple_before_complex,
reference_response,
status_code_patterns,
status_code_precedence,
text_response,
)


class ResponsesEndpoints:
Expand All @@ -26,3 +33,24 @@ def reference_response(cls) -> types.ModuleType:
Endpoint using predefined response
"""
return reference_response

@classmethod
def default_status_code(cls) -> types.ModuleType:
"""
Default Status Code Only
"""
return default_status_code

@classmethod
def status_code_patterns(cls) -> types.ModuleType:
"""
Status Code Patterns
"""
return status_code_patterns

@classmethod
def status_code_precedence(cls) -> types.ModuleType:
"""
Verify that specific status codes are always checked first, then ranges, then default
"""
return status_code_precedence
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def _get_kwargs(
def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]:
if response.status_code == 200:
return None

if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def _get_kwargs(
def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]:
if response.status_code == 200:
return None

if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def _get_kwargs(
def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]:
if response.status_code == 200:
return None

if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: htt
if response.status_code == 200:
response_200 = cast(str, response.json())
return response_200

if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def _get_kwargs(
def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]:
if response.status_code == 200:
return None

if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
Expand Down
Loading
Loading