litestar-google-errors 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,33 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: astral-sh/setup-uv@v6
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+ enable-cache: true
24
+ - run: uv sync --locked
25
+ - run: uv run pytest
26
+
27
+ build:
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: astral-sh/setup-uv@v6
32
+ - run: uv build
33
+ - run: uvx twine check --strict dist/*
@@ -0,0 +1,61 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: astral-sh/setup-uv@v6
16
+ - name: Check tag matches project version
17
+ run: |
18
+ version=$(uv version --short)
19
+ tag="${GITHUB_REF_NAME#v}"
20
+ if [ "${tag}" != "${version}" ]; then
21
+ echo "::error::Release tag ${GITHUB_REF_NAME} does not match project version ${version} in pyproject.toml"
22
+ exit 1
23
+ fi
24
+ - run: uv sync --locked
25
+ - run: uv run pytest
26
+ - run: uv build
27
+ - run: uvx twine check --strict dist/*
28
+ - uses: actions/upload-artifact@v4
29
+ with:
30
+ name: dist
31
+ path: dist/
32
+
33
+ publish:
34
+ needs: build
35
+ runs-on: ubuntu-latest
36
+ environment:
37
+ name: pypi
38
+ url: https://pypi.org/p/litestar-google-errors
39
+ permissions:
40
+ id-token: write
41
+ steps:
42
+ - uses: actions/download-artifact@v4
43
+ with:
44
+ name: dist
45
+ path: dist/
46
+ - uses: pypa/gh-action-pypi-publish@release/v1
47
+
48
+ upload-release-assets:
49
+ needs: publish
50
+ runs-on: ubuntu-latest
51
+ permissions:
52
+ contents: write
53
+ steps:
54
+ - uses: actions/download-artifact@v4
55
+ with:
56
+ name: dist
57
+ path: dist/
58
+ - name: Attach distributions to the GitHub release
59
+ env:
60
+ GH_TOKEN: ${{ github.token }}
61
+ run: gh release upload "$GITHUB_REF_NAME" dist/* --repo "$GITHUB_REPOSITORY" --clobber
@@ -0,0 +1,5 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ dist/
5
+ .pytest_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 alexkorolex
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.5
2
+ Name: litestar-google-errors
3
+ Version: 0.1.1
4
+ Summary: Litestar plugin for Google JSON style error responses in OpenAPI (Swagger) schemas, with typed msgspec error models
5
+ Project-URL: Homepage, https://github.com/alexkorolex/litestar-google-errors
6
+ Project-URL: Repository, https://github.com/alexkorolex/litestar-google-errors
7
+ Project-URL: Issues, https://github.com/alexkorolex/litestar-google-errors/issues
8
+ Author: alexkorolex
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: asgi,error-handling,errors,google-json-style,http-exception,json-api,litestar,litestar-plugin,msgspec,openapi,rest-api,swagger
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Framework :: Litestar
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: litestar<3,>=2.16
26
+ Description-Content-Type: text/markdown
27
+
28
+ # litestar-google-errors
29
+
30
+ [![PyPI](https://img.shields.io/pypi/v/litestar-google-errors.svg)](https://pypi.org/project/litestar-google-errors/)
31
+ [![Python versions](https://img.shields.io/pypi/pyversions/litestar-google-errors.svg)](https://pypi.org/project/litestar-google-errors/)
32
+ [![CI](https://github.com/alexkorolex/litestar-google-errors/actions/workflows/ci.yml/badge.svg)](https://github.com/alexkorolex/litestar-google-errors/actions/workflows/ci.yml)
33
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/alexkorolex/litestar-google-errors/blob/main/LICENSE)
34
+
35
+ **Google JSON style error responses for [Litestar](https://litestar.dev) OpenAPI.**
36
+
37
+ `litestar-google-errors` is a Litestar plugin that documents `HTTPException` error responses in
38
+ the OpenAPI (Swagger) schema using the
39
+ [Google JSON Style Guide](https://google.github.io/styleguide/jsoncstyleguide.xml#error) error
40
+ format, instead of Litestar's default `{"status_code", "detail", "extra"}` body. It also ships
41
+ typed `msgspec` models to return the same error shape from your API at runtime.
42
+
43
+ ## Features
44
+
45
+ - Documents error responses in the OpenAPI schema using the Google JSON error format
46
+ - Covers every exception listed in a route handler's `raises=[...]`
47
+ - Combines exceptions that share an HTTP status code with `oneOf`
48
+ - Lets you configure the example `domain`, `locationType` and `location`
49
+ - Ships typed `msgspec` models (`GoogleErrorResponse`, `GoogleError`, `GoogleErrorItem`) for runtime error bodies
50
+ - Includes `py.typed` for type checkers
51
+ - Supports Python 3.10+ and Litestar 2.16+
52
+
53
+ ## Litestar error format: before and after
54
+
55
+ Litestar's default error body:
56
+
57
+ ```json
58
+ {
59
+ "status_code": 404,
60
+ "detail": "Order not found"
61
+ }
62
+ ```
63
+
64
+ Google JSON style error body, as documented by this plugin:
65
+
66
+ ```json
67
+ {
68
+ "error": {
69
+ "code": 404,
70
+ "message": "Order not found",
71
+ "errors": [
72
+ {
73
+ "domain": "global",
74
+ "reason": "OrderNotFound",
75
+ "message": "Order not found",
76
+ "locationType": "endpoint",
77
+ "location": "/example"
78
+ }
79
+ ]
80
+ }
81
+ }
82
+ ```
83
+
84
+ ## Installation
85
+
86
+ ```bash
87
+ pip install litestar-google-errors
88
+ # or
89
+ uv add litestar-google-errors
90
+ ```
91
+
92
+ ## Quick start
93
+
94
+ Register the plugin on your Litestar app:
95
+
96
+ ```python
97
+ from litestar import Litestar
98
+ from litestar_google_errors import GoogleErrorResponsesPlugin
99
+
100
+ app = Litestar(
101
+ route_handlers=[...],
102
+ plugins=[GoogleErrorResponsesPlugin()],
103
+ )
104
+ ```
105
+
106
+ Every exception listed in a handler's `raises=[...]` appears in the OpenAPI schema in the Google
107
+ format. Exceptions that share a status code are combined with `oneOf`.
108
+
109
+ ### Configure the OpenAPI examples
110
+
111
+ ```python
112
+ GoogleErrorResponsesPlugin(domain="orders", location_type="path", example_location="/orders/1")
113
+ ```
114
+
115
+ ### Return Google-style errors at runtime
116
+
117
+ The plugin only changes the **OpenAPI documentation**. To return the same JSON error shape from
118
+ your API, use the bundled `msgspec` models in a Litestar exception handler:
119
+
120
+ ```python
121
+ from litestar import MediaType, Request, Response
122
+ from litestar.exceptions import HTTPException
123
+ from litestar_google_errors import GoogleError, GoogleErrorItem, GoogleErrorResponse, LocationType
124
+
125
+
126
+ def http_exception_handler(request: Request, exc: HTTPException) -> Response[GoogleErrorResponse]:
127
+ body = GoogleErrorResponse(
128
+ error=GoogleError(
129
+ code=exc.status_code,
130
+ message=exc.detail,
131
+ errors=[
132
+ GoogleErrorItem(
133
+ domain="global",
134
+ reason=type(exc).__name__,
135
+ message=exc.detail,
136
+ locationType=LocationType.ENDPOINT,
137
+ location=request.url.path,
138
+ )
139
+ ],
140
+ )
141
+ )
142
+ return Response(body, status_code=exc.status_code, media_type=MediaType.JSON)
143
+
144
+
145
+ app = Litestar(
146
+ route_handlers=[...],
147
+ plugins=[GoogleErrorResponsesPlugin()],
148
+ exception_handlers={HTTPException: http_exception_handler},
149
+ )
150
+ ```
151
+
152
+ ## Limitations
153
+
154
+ Litestar has no public hook for error response schemas, so the plugin replaces the private
155
+ `litestar._openapi.responses.create_error_responses` function. The replacement is process-wide,
156
+ and the dependency is pinned to `litestar<3` because that internal may change.
157
+
158
+ ## Development
159
+
160
+ ```bash
161
+ uv sync
162
+ uv run pytest
163
+ uv build
164
+ ```
165
+
166
+ ## License
167
+
168
+ [MIT](https://github.com/alexkorolex/litestar-google-errors/blob/main/LICENSE)
@@ -0,0 +1,141 @@
1
+ # litestar-google-errors
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/litestar-google-errors.svg)](https://pypi.org/project/litestar-google-errors/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/litestar-google-errors.svg)](https://pypi.org/project/litestar-google-errors/)
5
+ [![CI](https://github.com/alexkorolex/litestar-google-errors/actions/workflows/ci.yml/badge.svg)](https://github.com/alexkorolex/litestar-google-errors/actions/workflows/ci.yml)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/alexkorolex/litestar-google-errors/blob/main/LICENSE)
7
+
8
+ **Google JSON style error responses for [Litestar](https://litestar.dev) OpenAPI.**
9
+
10
+ `litestar-google-errors` is a Litestar plugin that documents `HTTPException` error responses in
11
+ the OpenAPI (Swagger) schema using the
12
+ [Google JSON Style Guide](https://google.github.io/styleguide/jsoncstyleguide.xml#error) error
13
+ format, instead of Litestar's default `{"status_code", "detail", "extra"}` body. It also ships
14
+ typed `msgspec` models to return the same error shape from your API at runtime.
15
+
16
+ ## Features
17
+
18
+ - Documents error responses in the OpenAPI schema using the Google JSON error format
19
+ - Covers every exception listed in a route handler's `raises=[...]`
20
+ - Combines exceptions that share an HTTP status code with `oneOf`
21
+ - Lets you configure the example `domain`, `locationType` and `location`
22
+ - Ships typed `msgspec` models (`GoogleErrorResponse`, `GoogleError`, `GoogleErrorItem`) for runtime error bodies
23
+ - Includes `py.typed` for type checkers
24
+ - Supports Python 3.10+ and Litestar 2.16+
25
+
26
+ ## Litestar error format: before and after
27
+
28
+ Litestar's default error body:
29
+
30
+ ```json
31
+ {
32
+ "status_code": 404,
33
+ "detail": "Order not found"
34
+ }
35
+ ```
36
+
37
+ Google JSON style error body, as documented by this plugin:
38
+
39
+ ```json
40
+ {
41
+ "error": {
42
+ "code": 404,
43
+ "message": "Order not found",
44
+ "errors": [
45
+ {
46
+ "domain": "global",
47
+ "reason": "OrderNotFound",
48
+ "message": "Order not found",
49
+ "locationType": "endpoint",
50
+ "location": "/example"
51
+ }
52
+ ]
53
+ }
54
+ }
55
+ ```
56
+
57
+ ## Installation
58
+
59
+ ```bash
60
+ pip install litestar-google-errors
61
+ # or
62
+ uv add litestar-google-errors
63
+ ```
64
+
65
+ ## Quick start
66
+
67
+ Register the plugin on your Litestar app:
68
+
69
+ ```python
70
+ from litestar import Litestar
71
+ from litestar_google_errors import GoogleErrorResponsesPlugin
72
+
73
+ app = Litestar(
74
+ route_handlers=[...],
75
+ plugins=[GoogleErrorResponsesPlugin()],
76
+ )
77
+ ```
78
+
79
+ Every exception listed in a handler's `raises=[...]` appears in the OpenAPI schema in the Google
80
+ format. Exceptions that share a status code are combined with `oneOf`.
81
+
82
+ ### Configure the OpenAPI examples
83
+
84
+ ```python
85
+ GoogleErrorResponsesPlugin(domain="orders", location_type="path", example_location="/orders/1")
86
+ ```
87
+
88
+ ### Return Google-style errors at runtime
89
+
90
+ The plugin only changes the **OpenAPI documentation**. To return the same JSON error shape from
91
+ your API, use the bundled `msgspec` models in a Litestar exception handler:
92
+
93
+ ```python
94
+ from litestar import MediaType, Request, Response
95
+ from litestar.exceptions import HTTPException
96
+ from litestar_google_errors import GoogleError, GoogleErrorItem, GoogleErrorResponse, LocationType
97
+
98
+
99
+ def http_exception_handler(request: Request, exc: HTTPException) -> Response[GoogleErrorResponse]:
100
+ body = GoogleErrorResponse(
101
+ error=GoogleError(
102
+ code=exc.status_code,
103
+ message=exc.detail,
104
+ errors=[
105
+ GoogleErrorItem(
106
+ domain="global",
107
+ reason=type(exc).__name__,
108
+ message=exc.detail,
109
+ locationType=LocationType.ENDPOINT,
110
+ location=request.url.path,
111
+ )
112
+ ],
113
+ )
114
+ )
115
+ return Response(body, status_code=exc.status_code, media_type=MediaType.JSON)
116
+
117
+
118
+ app = Litestar(
119
+ route_handlers=[...],
120
+ plugins=[GoogleErrorResponsesPlugin()],
121
+ exception_handlers={HTTPException: http_exception_handler},
122
+ )
123
+ ```
124
+
125
+ ## Limitations
126
+
127
+ Litestar has no public hook for error response schemas, so the plugin replaces the private
128
+ `litestar._openapi.responses.create_error_responses` function. The replacement is process-wide,
129
+ and the dependency is pinned to `litestar<3` because that internal may change.
130
+
131
+ ## Development
132
+
133
+ ```bash
134
+ uv sync
135
+ uv run pytest
136
+ uv build
137
+ ```
138
+
139
+ ## License
140
+
141
+ [MIT](https://github.com/alexkorolex/litestar-google-errors/blob/main/LICENSE)
@@ -0,0 +1,55 @@
1
+ [project]
2
+ name = "litestar-google-errors"
3
+ version = "0.1.1"
4
+ description = "Litestar plugin for Google JSON style error responses in OpenAPI (Swagger) schemas, with typed msgspec error models"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "MIT"
8
+ authors = [{ name = "alexkorolex" }]
9
+ keywords = [
10
+ "litestar",
11
+ "litestar-plugin",
12
+ "openapi",
13
+ "swagger",
14
+ "errors",
15
+ "error-handling",
16
+ "http-exception",
17
+ "google-json-style",
18
+ "json-api",
19
+ "msgspec",
20
+ "asgi",
21
+ "rest-api",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 4 - Beta",
25
+ "Framework :: Litestar",
26
+ "Intended Audience :: Developers",
27
+ "Operating System :: OS Independent",
28
+ "Programming Language :: Python :: 3",
29
+ "Programming Language :: Python :: 3 :: Only",
30
+ "Programming Language :: Python :: 3.10",
31
+ "Programming Language :: Python :: 3.11",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Programming Language :: Python :: 3.13",
34
+ "Topic :: Internet :: WWW/HTTP",
35
+ "Typing :: Typed",
36
+ ]
37
+ dependencies = ["litestar>=2.16,<3"]
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/alexkorolex/litestar-google-errors"
41
+ Repository = "https://github.com/alexkorolex/litestar-google-errors"
42
+ Issues = "https://github.com/alexkorolex/litestar-google-errors/issues"
43
+
44
+ [dependency-groups]
45
+ dev = ["pytest>=8", "httpx>=0.27"]
46
+
47
+ [build-system]
48
+ requires = ["hatchling"]
49
+ build-backend = "hatchling.build"
50
+
51
+ [tool.hatch.build.targets.wheel]
52
+ packages = ["src/litestar_google_errors"]
53
+
54
+ [tool.pytest.ini_options]
55
+ testpaths = ["tests"]
@@ -0,0 +1,12 @@
1
+ from litestar_google_errors.models import GoogleError, GoogleErrorItem, GoogleErrorResponse, LocationType
2
+ from litestar_google_errors.openapi import create_error_responses
3
+ from litestar_google_errors.plugin import GoogleErrorResponsesPlugin
4
+
5
+ __all__ = (
6
+ "GoogleError",
7
+ "GoogleErrorItem",
8
+ "GoogleErrorResponse",
9
+ "GoogleErrorResponsesPlugin",
10
+ "LocationType",
11
+ "create_error_responses",
12
+ )
@@ -0,0 +1,40 @@
1
+ """Google JSON style error payload models."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from enum import Enum
6
+ from typing import Optional
7
+
8
+ from msgspec import Struct
9
+
10
+ __all__ = ("GoogleError", "GoogleErrorItem", "GoogleErrorResponse", "LocationType")
11
+
12
+
13
+ class LocationType(str, Enum):
14
+ FIELD = "field"
15
+ PARAMETER = "parameter"
16
+ PATH = "path"
17
+ HEADER = "header"
18
+ BODY = "body"
19
+ QUERY = "query"
20
+ COOKIE = "cookie"
21
+ ENDPOINT = "endpoint"
22
+ DOMAIN = "domain"
23
+
24
+
25
+ class GoogleErrorItem(Struct):
26
+ domain: str
27
+ reason: str
28
+ message: str
29
+ locationType: Optional[str] = None
30
+ location: Optional[str] = None
31
+
32
+
33
+ class GoogleError(Struct):
34
+ errors: list[GoogleErrorItem]
35
+ code: int
36
+ message: str
37
+
38
+
39
+ class GoogleErrorResponse(Struct):
40
+ error: GoogleError
@@ -0,0 +1,114 @@
1
+ """OpenAPI schema generation for Google JSON style error responses."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import contextlib
6
+ from http import HTTPStatus
7
+ from typing import Iterator
8
+
9
+ from litestar import MediaType
10
+ from litestar.exceptions import HTTPException
11
+ from litestar.openapi.spec import OpenAPIMediaType, OpenAPIResponse, OpenAPIType, Schema
12
+
13
+ __all__ = ("create_error_responses",)
14
+
15
+
16
+ def _status_phrase(status_code: int) -> str:
17
+ with contextlib.suppress(ValueError):
18
+ return HTTPStatus(status_code).phrase
19
+ return ""
20
+
21
+
22
+ def _status_description(status_code: int) -> str:
23
+ with contextlib.suppress(ValueError):
24
+ return HTTPStatus(status_code).description
25
+ return ""
26
+
27
+
28
+ def _error_schema(
29
+ exc: type[HTTPException],
30
+ status_code: int,
31
+ detail: str,
32
+ domain: str,
33
+ location_type: str,
34
+ location: str,
35
+ ) -> Schema:
36
+ return Schema(
37
+ type=OpenAPIType.OBJECT,
38
+ required=["error"],
39
+ description=exc.__name__,
40
+ properties={
41
+ "error": Schema(
42
+ type=OpenAPIType.OBJECT,
43
+ required=["code", "message", "errors"],
44
+ properties={
45
+ "code": Schema(type=OpenAPIType.INTEGER),
46
+ "message": Schema(type=OpenAPIType.STRING),
47
+ "errors": Schema(
48
+ type=OpenAPIType.ARRAY,
49
+ items=Schema(
50
+ type=OpenAPIType.OBJECT,
51
+ required=["domain", "reason", "message"],
52
+ properties={
53
+ "domain": Schema(type=OpenAPIType.STRING),
54
+ "reason": Schema(type=OpenAPIType.STRING),
55
+ "message": Schema(type=OpenAPIType.STRING),
56
+ "locationType": Schema(type=[OpenAPIType.STRING, OpenAPIType.NULL]),
57
+ "location": Schema(type=[OpenAPIType.STRING, OpenAPIType.NULL]),
58
+ },
59
+ ),
60
+ ),
61
+ },
62
+ )
63
+ },
64
+ examples=[
65
+ {
66
+ "error": {
67
+ "code": status_code,
68
+ "message": detail,
69
+ "errors": [
70
+ {
71
+ "domain": domain,
72
+ "reason": exc.__name__,
73
+ "message": detail,
74
+ "locationType": location_type,
75
+ "location": location,
76
+ }
77
+ ],
78
+ }
79
+ }
80
+ ],
81
+ )
82
+
83
+
84
+ def create_error_responses(
85
+ exceptions: list[type[HTTPException]],
86
+ *,
87
+ domain: str = "global",
88
+ location_type: str = "endpoint",
89
+ location: str = "/example",
90
+ ) -> Iterator[tuple[str, OpenAPIResponse]]:
91
+ """Create OpenAPI responses for ``exceptions`` in the Google JSON error format.
92
+
93
+ Exceptions sharing a status code are combined into a single response using ``oneOf``.
94
+ """
95
+ grouped: dict[int, list[type[HTTPException]]] = {}
96
+ for exc in exceptions:
97
+ grouped.setdefault(getattr(exc, "status_code", 500), []).append(exc)
98
+
99
+ for status_code, group in grouped.items():
100
+ description = ""
101
+ schemas: list[Schema] = []
102
+ for exc in group:
103
+ detail = getattr(exc, "detail", None) or _status_phrase(status_code)
104
+ description = description or getattr(exc, "detail", None) or ""
105
+ schemas.append(_error_schema(exc, status_code, detail, domain, location_type, location))
106
+
107
+ schema = schemas[0] if len(schemas) == 1 else Schema(one_of=schemas)
108
+ yield (
109
+ str(status_code),
110
+ OpenAPIResponse(
111
+ description=description or _status_description(status_code),
112
+ content={MediaType.JSON: OpenAPIMediaType(schema=schema)},
113
+ ),
114
+ )