<h3 dir="auto">First check</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I added a very descriptive title to this issue.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I used the GitHub search to find a similar issue and didn't find it.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I searched the FastAPI documentation, with the integrated search.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already searched in Google "How to X in FastAPI" and didn't find any information.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already read and followed all the tutorial in the docs and didn't find an answer.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already checked if it is not related to FastAPI but to <a href="https://github.com/samuelcolvin/pydantic">Pydantic</a>.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already checked if it is not related to FastAPI but to <a href="https://github.com/swagger-api/swagger-ui">Swagger UI</a>.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already checked if it is not related to FastAPI but to <a href="https://github.com/Redocly/redoc">ReDoc</a>.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> After submitting this, I commit to:
<ul dir="auto">
<li>Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.</li>
<li>Or, I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.</li>
<li>Implement a Pull Request for a confirmed bug.</li>
</ul>
</li>
</ul>

<h3 dir="auto">Example</h3>
<p dir="auto">I would like to be able to do this:</p>

<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from fastapi import FastAPI, Query

app = FastAPI()


@app.get(&quot;/&quot;)
def get(query: Optional[str] = Query(None, alias=['q', 'query']):
    return query"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">fastapi</span> <span class="pl-k">import</span> <span class="pl-v">FastAPI</span>, <span class="pl-v">Query</span>

<span class="pl-s1">app</span> <span class="pl-c1">=</span> <span class="pl-v">FastAPI</span>()


<span class="pl-en">@<span class="pl-s1">app</span>.<span class="pl-en">get</span>(<span class="pl-s">"/"</span>)</span>
<span class="pl-k">def</span> <span class="pl-en">get</span>(<span class="pl-s1">query</span>: <span class="pl-v">Optional</span>[<span class="pl-s1">str</span>] <span class="pl-c1">=</span> <span class="pl-v">Query</span>(<span class="pl-c1">None</span>, <span class="pl-s1">alias</span><span class="pl-c1">=</span>[<span class="pl-s">'q'</span>, <span class="pl-s">'query'</span>]):
    <span class="pl-k">return</span> <span class="pl-s1">query</span></pre></div>
<h3 dir="auto">Description</h3>

<p dir="auto">Currently to give a query parameter multiple aliases, you need to declare multiple query parameters.</p>
<h3 dir="auto">The solution you would like</h3>

<p dir="auto">Being able to give a list of aliases to the <code class="notranslate">alias</code> arg of the <code class="notranslate">Query</code> class.</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="Query(alias=['q', 'query'])"><pre class="notranslate"><span class="pl-v">Query</span>(<span class="pl-s1">alias</span><span class="pl-c1">=</span>[<span class="pl-s">'q'</span>, <span class="pl-s">'query'</span>])</pre></div>
<p dir="auto">Of course backwards compatibility won'y break, as  <code class="notranslate">alias</code> arg would be of type <code class="notranslate">Optional[Union[str, Iterable[str]]]</code>.<br>
You would still be able to do this:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="Query(alias='q')"><pre class="notranslate"><span class="pl-v">Query</span>(<span class="pl-s1">alias</span><span class="pl-c1">=</span><span class="pl-s">'q'</span>)</pre></div>
<h3 dir="auto">Describe alternatives you've considered</h3>

<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/Kludex/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/Kludex">@Kludex</a> mentioned creating a new argument <code class="notranslate">aliases</code></p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="Query(aliases=['q', 'query'])"><pre class="notranslate"><span class="pl-v">Query</span>(<span class="pl-s1">aliases</span><span class="pl-c1">=</span>[<span class="pl-s">'q'</span>, <span class="pl-s">'query'</span>])</pre></div>
<p dir="auto">(Duplicate of <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1373268307" data-permission-text="Title is private" data-url="https://github.com/tiangolo/fastapi/issues/5390" data-hovercard-type="pull_request" data-hovercard-url="/tiangolo/fastapi/pull/5390/hovercard" href="https://github.com/tiangolo/fastapi/pull/5390">#5390</a>)</p>
<h3 dir="auto">First Check</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I added a very descriptive title to this issue.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I used the GitHub search to find a similar issue and didn't find it.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I searched the FastAPI documentation, with the integrated search.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already searched in Google "How to X in FastAPI" and didn't find any information.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already read and followed all the tutorial in the docs and didn't find an answer.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already checked if it is not related to FastAPI but to <a href="https://github.com/samuelcolvin/pydantic">Pydantic</a>.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already checked if it is not related to FastAPI but to <a href="https://github.com/swagger-api/swagger-ui">Swagger UI</a>.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I already checked if it is not related to FastAPI but to <a href="https://github.com/Redocly/redoc">ReDoc</a>.</li>
</ul>
<h3 dir="auto">Commit to Help</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I commit to help with one of those options <g-emoji class="g-emoji" alias="point_up_2" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f446.png">👆</g-emoji></li>
</ul>
<h3 dir="auto">Example Code</h3>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# N/A"><pre class="notranslate"><span class="pl-c"># N/A</span></pre></div>
<h3 dir="auto">Description</h3>
<p dir="auto">I'd like to be able to implement a multimedia route that can optimally handle not only an entire e.g. msgpacked payload, but individual fields in the payload.</p>
<p dir="auto">For example, if some models include <code class="notranslate">bytes</code> fields, for optimal performance, you want those fields to be (de)serialized only once, i.e. msgpack/base64 to <code class="notranslate">bytes</code> or <code class="notranslate">bytes</code> to msgpack/base64, instead of, e.g., msgpack to base64 to <code class="notranslate">bytes</code>.</p>
<h3 dir="auto">Wanted Solution</h3>
<p dir="auto">Building on top of the contributions of <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/dmontagu/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/dmontagu">@dmontagu</a>, <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/sandys/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/sandys">@sandys</a>, and <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/jcsaaddupuy/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/jcsaaddupuy">@jcsaaddupuy</a> in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="492250076" data-permission-text="Title is private" data-url="https://github.com/tiangolo/fastapi/issues/521" data-hovercard-type="issue" data-hovercard-url="/tiangolo/fastapi/issues/521/hovercard" href="https://github.com/tiangolo/fastapi/issues/521">#521</a>, in particular <a href="https://github.com/tiangolo/fastapi/issues/521#issuecomment-646989249" data-hovercard-type="issue" data-hovercard-url="/tiangolo/fastapi/issues/521/hovercard">this comment</a>, I'd like for <code class="notranslate">get_route_handler()</code> to be able to pass a <code class="notranslate">custom_encoder</code> to <code class="notranslate">get_request_handler()</code>, and for <code class="notranslate">get_request_handler()</code> to be able to pass <code class="notranslate">custom_encoder</code> to <code class="notranslate">serialize_response()</code>.</p>
<p dir="auto">By being able to pass a custom msgpack encoder to <code class="notranslate">get_request_handler()</code>, you could suppress base64-encoding of custom e.g. <code class="notranslate">Base64Bytes</code> fields by overriding their encoders with <code class="notranslate">lambda x: x</code> identity passthroughs, while utilizing the existing <code class="notranslate">jsonable_encoder()</code> and <code class="notranslate">custom_encoder</code> mechanisms, without resorting to any hackery such as dynamically patching models' <code class="notranslate">.__config__.json_encoders</code>.</p>
<h3 dir="auto">Wanted Code</h3>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# Copy-paste from tests/test_advanced_custom_route_class.py
# in https://github.com/natskvi/fastapi/tree/multimedia-route-support
# Requires a few more tests before it is PR-ready.

from collections import defaultdict
import msgpack
from typing import Any, Callable, Dict, Final
import pytest
import base64
import fastapi
from fastapi import APIRouter, FastAPI, status
from fastapi.routing import APIRoute, get_request_handler
from fastapi.testclient import TestClient
from pydantic import BaseModel
from starlette.requests import Request
from starlette.responses import Response
from starlette.routing import Route

app = FastAPI()


ACCEPT: Final = &quot;accept&quot;
CONTENT_TYPE: Final = &quot;content-type&quot;
JSON: Final = &quot;application/json&quot;
MSGPACK: Final = &quot;application/x-msgpack&quot;


class Base64Bytes(bytes):
    &quot;&quot;&quot;Defines a Pydantic custom field type for deserializing base64
    string to bytes.&quot;&quot;&quot;

    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, value) -&gt; &quot;Base64Bytes&quot;:
        if isinstance(value, str):
            value = base64.b64decode(value)
        return cls(value)


def base64_encode_as_str(data: bytes) -&gt; str:
    &quot;&quot;&quot;base64-encode binary data as ASCII string&quot;&quot;&quot;
    return base64.b64encode(data).decode('ascii')


custom_json_encoder = {
    Base64Bytes: base64_encode_as_str,  # Overrides Pydantic default `lambda o: o.decode()`
}


_catchall_encoder_saved = fastapi.encoders.catchall_encoder
# fastapi.encoders.catchall_encoder callable is applied by default to obj
# (if obj is not None) after the logic that handles primitives, dicts, lists,
# tuples, Pydantic models, etc. (applying models'  __config__.json_encoders,
# custom encoders, pydantic.json.ENCODERS_BY_TYPE).
fastapi.encoders.catchall_encoder = str


# Override default encoders for raw bytes fields to skip base64-encoding
# when using msgpack to serialize response payloads.
msgpack_encoder_override = defaultdict(
    lambda: str,
    {
        Base64Bytes: lambda x: x,  # Overrides custom_json_encoder's `base64_encode_as_str`
    },
)


class MsgpackRequest(Request):
    &quot;&quot;&quot;Msgpack request class, used only if the request headers include
    'Content-Type: application/x-msgpack'.&quot;&quot;&quot;

    media_type = MSGPACK

    async def body(self) -&gt; bytes:
        if not hasattr(self, &quot;_body&quot;):
            body: Final = await super().body()
            if body:
                # fastapi.tiangolo.com/advanced/custom-request-and-route/#handling-custom-request-body-encodings
                self._body = msgpack.unpackb(body)
        return self._body


class MsgpackResponse(Response):
    &quot;&quot;&quot;Msgpack response class, used only if the request headers include
    'Accept: application/x-msgpack'.&quot;&quot;&quot;

    media_type = MSGPACK

    def render(self, content: Any) -&gt; bytes:
        return msgpack.packb(content)


class MultimediaRouteMixin(APIRoute):
    &quot;&quot;&quot;A route &quot;mixin&quot; that handles 'application/x-msgpack' in addition to
    'application/json'. Its generic design simplifies adding support for more
    mime types. (Hence, a more accurate name for this class would be
    `MultiMimeTypeRouteMixin`.)
    Credit:
    https://github.com/tiangolo/fastapi/issues/521#issuecomment-646989249&quot;&quot;&quot;

    REQUEST_CLASSES: Final = {
        MsgpackRequest.media_type: MsgpackRequest,
    }

    RESPONSE_CLASSES: Final = {
        MsgpackResponse.media_type: MsgpackResponse,
    }

    def _get_multimedia_request_handler(self, mime_type):
        # Use custom response class or fall back on default self.response_class.
        response_class = self.RESPONSE_CLASSES.get(mime_type, self.response_class)
        # Use msgpack override encoder for msgpack responses.
        custom_encoder = msgpack_encoder_override if mime_type == MSGPACK else None

        return get_request_handler(
            dependant=self.dependant,
            body_field=self.body_field,
            status_code=self.status_code,
            response_class=response_class,  # Based on mime_type (see above)
            response_field=self.secure_cloned_response_field,
            response_model_include=self.response_model_include,
            response_model_exclude=self.response_model_exclude,
            response_model_by_alias=self.response_model_by_alias,
            response_model_exclude_unset=self.response_model_exclude_unset,
            response_model_exclude_defaults=self.response_model_exclude_defaults,
            response_model_exclude_none=self.response_model_exclude_none,
            dependency_overrides_provider=self.dependency_overrides_provider,
            custom_encoder=custom_encoder,  # Based on mime_type (see above)
        )

    def get_route_handler(self) -&gt; Callable:
        &quot;&quot;&quot;Overrides APIRoute.get_route_handler()&quot;&quot;&quot;

        async def multimedia_route_handler(request: Request) -&gt; Response:

            content_type_headers = request.headers.get(&quot;Content-Type&quot;)
            try:
                request_cls = self.REQUEST_CLASSES[content_type_headers]
                request = request_cls(request.scope, request.receive)
            except KeyError:
                pass  # No handler for content_type, process request as-is.

            accept_headers = request.headers.get(&quot;Accept&quot;)
            route_handler = self._get_multimedia_request_handler(accept_headers)
            return await route_handler(request)

        return multimedia_route_handler


class ModelConfig:
    json_encoders = custom_json_encoder
    validate_assignment = True


class ModelWithBytes(BaseModel):
    text: str
    raw: Base64Bytes

    class Config(ModelConfig):
        pass


TEXT: Final =&quot;text&quot;
BYTES: Final = b&quot;\x16\r\xd4)\x93&gt;(\x04\x83\xcc\xc5\xd6&quot;


test_dict = {
    &quot;text&quot;: TEXT,
    &quot;raw&quot;: BYTES,
}

base64_encoded_test_dict = {
    &quot;text&quot;: TEXT,
    &quot;raw&quot;: base64_encode_as_str(BYTES),
}


router = APIRouter(route_class=MultimediaRouteMixin)


@router.post(&quot;&quot;)
def post_test_model(body: ModelWithBytes) -&gt; ModelWithBytes:
    assert body == ModelWithBytes(text=TEXT, raw=BYTES)
    assert ModelConfig.json_encoders[Base64Bytes] is base64_encode_as_str
    # Verify jsonable_encoder did not mutate body
    # TODO: assert Base64Bytes not in body.__config__.json_encoders
    return body


ENDPOINT_PATH: Final = &quot;/test_multimedia&quot;

app.include_router(router=router, prefix=ENDPOINT_PATH)

client = TestClient(app)


def test_multimedia_route():
    &quot;&quot;&quot;Test multimedia &quot;middleware&quot; (route mixin) for a simple payload
    that includes raw bytes for two combinations of  'Accept' and
    'Content-Type' HTTP headers.&quot;&quot;&quot;

    # Test JSON-to-JSON POST
    for headers in (
        {},
        {ACCEPT: JSON},
        {CONTENT_TYPE: JSON},
        {ACCEPT: JSON, CONTENT_TYPE: JSON},
    ):
        resp = client.post(
            ENDPOINT_PATH,
            json=base64_encoded_test_dict,
            headers=headers,
        )
        assert resp.ok
        result = resp.json()
        assert resp.status_code == status.HTTP_200_OK
        assert result == base64_encoded_test_dict

    # Test JSON-to-msgpack POST
    for headers in (
        {ACCEPT: MSGPACK},
        {ACCEPT: MSGPACK, CONTENT_TYPE: JSON},
    ):
        resp = client.post(
            ENDPOINT_PATH,
            headers=headers,
            json=base64_encoded_test_dict,
        )
        assert resp.ok
        assert resp.status_code == status.HTTP_200_OK
        result = msgpack.unpackb(resp.content)
        assert result == test_dict

    # Test msgpack-to-JSON POST
    for headers in (
        {CONTENT_TYPE: MSGPACK},
        {ACCEPT: JSON, CONTENT_TYPE: MSGPACK},
    ):
        resp = client.post(
            ENDPOINT_PATH,
            headers=headers,
            data=msgpack.packb(test_dict),
        )
        assert resp.ok
        result = resp.json()
        assert resp.status_code == status.HTTP_200_OK
        assert result == base64_encoded_test_dict

    # Test msgpack-to-msgpack POST
    for headers in (
        {ACCEPT: MSGPACK, CONTENT_TYPE: MSGPACK},
    ):
        resp = client.post(
            ENDPOINT_PATH,
            headers=headers,
            data=msgpack.packb(test_dict),
        )
        assert resp.ok
        assert resp.status_code == status.HTTP_200_OK
        result = msgpack.unpackb(resp.content)
        assert result == test_dict

    # Test for error when sending JSON but expecting msgpack
    resp = client.post(
        ENDPOINT_PATH,
        headers={CONTENT_TYPE: MSGPACK},
        json=base64_encoded_test_dict,
    )
    assert not resp.ok
    assert resp.status_code == status.HTTP_400_BAD_REQUEST

    # Test for error when sending msgpack but expecting JSON
    resp = client.post(
        ENDPOINT_PATH,
        headers={CONTENT_TYPE: JSON},
        data=msgpack.packb(test_dict),
    )
    assert not resp.ok
    assert resp.status_code == status.HTTP_400_BAD_REQUEST


# Restore pre-test state
fastapi.encoders.catchall_encoder = _catchall_encoder_saved"><pre class="notranslate"><span class="pl-c"># Copy-paste from tests/test_advanced_custom_route_class.py</span>
<span class="pl-c"># in https://github.com/natskvi/fastapi/tree/multimedia-route-support</span>
<span class="pl-c"># Requires a few more tests before it is PR-ready.</span>

<span class="pl-k">from</span> <span class="pl-s1">collections</span> <span class="pl-k">import</span> <span class="pl-s1">defaultdict</span>
<span class="pl-k">import</span> <span class="pl-s1">msgpack</span>
<span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">Any</span>, <span class="pl-v">Callable</span>, <span class="pl-v">Dict</span>, <span class="pl-v">Final</span>
<span class="pl-k">import</span> <span class="pl-s1">pytest</span>
<span class="pl-k">import</span> <span class="pl-s1">base64</span>
<span class="pl-k">import</span> <span class="pl-s1">fastapi</span>
<span class="pl-k">from</span> <span class="pl-s1">fastapi</span> <span class="pl-k">import</span> <span class="pl-v">APIRouter</span>, <span class="pl-v">FastAPI</span>, <span class="pl-s1">status</span>
<span class="pl-k">from</span> <span class="pl-s1">fastapi</span>.<span class="pl-s1">routing</span> <span class="pl-k">import</span> <span class="pl-v">APIRoute</span>, <span class="pl-s1">get_request_handler</span>
<span class="pl-k">from</span> <span class="pl-s1">fastapi</span>.<span class="pl-s1">testclient</span> <span class="pl-k">import</span> <span class="pl-v">TestClient</span>
<span class="pl-k">from</span> <span class="pl-s1">pydantic</span> <span class="pl-k">import</span> <span class="pl-v">BaseModel</span>
<span class="pl-k">from</span> <span class="pl-s1">starlette</span>.<span class="pl-s1">requests</span> <span class="pl-k">import</span> <span class="pl-v">Request</span>
<span class="pl-k">from</span> <span class="pl-s1">starlette</span>.<span class="pl-s1">responses</span> <span class="pl-k">import</span> <span class="pl-v">Response</span>
<span class="pl-k">from</span> <span class="pl-s1">starlette</span>.<span class="pl-s1">routing</span> <span class="pl-k">import</span> <span class="pl-v">Route</span>

<span class="pl-s1">app</span> <span class="pl-c1">=</span> <span class="pl-v">FastAPI</span>()


<span class="pl-v">ACCEPT</span>: <span class="pl-v">Final</span> <span class="pl-c1">=</span> <span class="pl-s">"accept"</span>
<span class="pl-v">CONTENT_TYPE</span>: <span class="pl-v">Final</span> <span class="pl-c1">=</span> <span class="pl-s">"content-type"</span>
<span class="pl-v">JSON</span>: <span class="pl-v">Final</span> <span class="pl-c1">=</span> <span class="pl-s">"application/json"</span>
<span class="pl-v">MSGPACK</span>: <span class="pl-v">Final</span> <span class="pl-c1">=</span> <span class="pl-s">"application/x-msgpack"</span>


<span class="pl-k">class</span> <span class="pl-v">Base64Bytes</span>(<span class="pl-s1">bytes</span>):
    <span class="pl-s">"""Defines a Pydantic custom field type for deserializing base64</span>
<span class="pl-s">    string to bytes."""</span>

    <span class="pl-en">@<span class="pl-s1">classmethod</span></span>
    <span class="pl-k">def</span> <span class="pl-en">__get_validators__</span>(<span class="pl-s1">cls</span>):
        <span class="pl-k">yield</span> <span class="pl-s1">cls</span>.<span class="pl-s1">validate</span>

    <span class="pl-en">@<span class="pl-s1">classmethod</span></span>
    <span class="pl-k">def</span> <span class="pl-en">validate</span>(<span class="pl-s1">cls</span>, <span class="pl-s1">value</span>) <span class="pl-c1">-&gt;</span> <span class="pl-s">"Base64Bytes"</span>:
        <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">value</span>, <span class="pl-s1">str</span>):
            <span class="pl-s1">value</span> <span class="pl-c1">=</span> <span class="pl-s1">base64</span>.<span class="pl-en">b64decode</span>(<span class="pl-s1">value</span>)
        <span class="pl-k">return</span> <span class="pl-en">cls</span>(<span class="pl-s1">value</span>)


<span class="pl-k">def</span> <span class="pl-en">base64_encode_as_str</span>(<span class="pl-s1">data</span>: <span class="pl-s1">bytes</span>) <span class="pl-c1">-&gt;</span> <span class="pl-s1">str</span>:
    <span class="pl-s">"""base64-encode binary data as ASCII string"""</span>
    <span class="pl-k">return</span> <span class="pl-s1">base64</span>.<span class="pl-en">b64encode</span>(<span class="pl-s1">data</span>).<span class="pl-en">decode</span>(<span class="pl-s">'ascii'</span>)


<span class="pl-s1">custom_json_encoder</span> <span class="pl-c1">=</span> {
    <span class="pl-v">Base64Bytes</span>: <span class="pl-s1">base64_encode_as_str</span>,  <span class="pl-c"># Overrides Pydantic default `lambda o: o.decode()`</span>
}


<span class="pl-s1">_catchall_encoder_saved</span> <span class="pl-c1">=</span> <span class="pl-s1">fastapi</span>.<span class="pl-s1">encoders</span>.<span class="pl-s1">catchall_encoder</span>
<span class="pl-c"># fastapi.encoders.catchall_encoder callable is applied by default to obj</span>
<span class="pl-c"># (if obj is not None) after the logic that handles primitives, dicts, lists,</span>
<span class="pl-c"># tuples, Pydantic models, etc. (applying models'  __config__.json_encoders,</span>
<span class="pl-c"># custom encoders, pydantic.json.ENCODERS_BY_TYPE).</span>
<span class="pl-s1">fastapi</span>.<span class="pl-s1">encoders</span>.<span class="pl-s1">catchall_encoder</span> <span class="pl-c1">=</span> <span class="pl-s1">str</span>


<span class="pl-c"># Override default encoders for raw bytes fields to skip base64-encoding</span>
<span class="pl-c"># when using msgpack to serialize response payloads.</span>
<span class="pl-s1">msgpack_encoder_override</span> <span class="pl-c1">=</span> <span class="pl-en">defaultdict</span>(
    <span class="pl-k">lambda</span>: <span class="pl-s1">str</span>,
    {
        <span class="pl-v">Base64Bytes</span>: <span class="pl-k">lambda</span> <span class="pl-s1">x</span>: <span class="pl-s1">x</span>,  <span class="pl-c"># Overrides custom_json_encoder's `base64_encode_as_str`</span>
    },
)


<span class="pl-k">class</span> <span class="pl-v">MsgpackRequest</span>(<span class="pl-v">Request</span>):
    <span class="pl-s">"""Msgpack request class, used only if the request headers include</span>
<span class="pl-s">    'Content-Type: application/x-msgpack'."""</span>

    <span class="pl-s1">media_type</span> <span class="pl-c1">=</span> <span class="pl-v">MSGPACK</span>

    <span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">body</span>(<span class="pl-s1">self</span>) <span class="pl-c1">-&gt;</span> <span class="pl-s1">bytes</span>:
        <span class="pl-k">if</span> <span class="pl-c1">not</span> <span class="pl-en">hasattr</span>(<span class="pl-s1">self</span>, <span class="pl-s">"_body"</span>):
            <span class="pl-s1">body</span>: <span class="pl-v">Final</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">super</span>().<span class="pl-en">body</span>()
            <span class="pl-k">if</span> <span class="pl-s1">body</span>:
                <span class="pl-c"># fastapi.tiangolo.com/advanced/custom-request-and-route/#handling-custom-request-body-encodings</span>
                <span class="pl-s1">self</span>.<span class="pl-s1">_body</span> <span class="pl-c1">=</span> <span class="pl-s1">msgpack</span>.<span class="pl-en">unpackb</span>(<span class="pl-s1">body</span>)
        <span class="pl-k">return</span> <span class="pl-s1">self</span>.<span class="pl-s1">_body</span>


<span class="pl-k">class</span> <span class="pl-v">MsgpackResponse</span>(<span class="pl-v">Response</span>):
    <span class="pl-s">"""Msgpack response class, used only if the request headers include</span>
<span class="pl-s">    'Accept: application/x-msgpack'."""</span>

    <span class="pl-s1">media_type</span> <span class="pl-c1">=</span> <span class="pl-v">MSGPACK</span>

    <span class="pl-k">def</span> <span class="pl-en">render</span>(<span class="pl-s1">self</span>, <span class="pl-s1">content</span>: <span class="pl-v">Any</span>) <span class="pl-c1">-&gt;</span> <span class="pl-s1">bytes</span>:
        <span class="pl-k">return</span> <span class="pl-s1">msgpack</span>.<span class="pl-en">packb</span>(<span class="pl-s1">content</span>)


<span class="pl-k">class</span> <span class="pl-v">MultimediaRouteMixin</span>(<span class="pl-v">APIRoute</span>):
    <span class="pl-s">"""A route "mixin" that handles 'application/x-msgpack' in addition to</span>
<span class="pl-s">    'application/json'. Its generic design simplifies adding support for more</span>
<span class="pl-s">    mime types. (Hence, a more accurate name for this class would be</span>
<span class="pl-s">    `MultiMimeTypeRouteMixin`.)</span>
<span class="pl-s">    Credit:</span>
<span class="pl-s">    https://github.com/tiangolo/fastapi/issues/521#issuecomment-646989249"""</span>

    <span class="pl-v">REQUEST_CLASSES</span>: <span class="pl-v">Final</span> <span class="pl-c1">=</span> {
        <span class="pl-v">MsgpackRequest</span>.<span class="pl-s1">media_type</span>: <span class="pl-v">MsgpackRequest</span>,
    }

    <span class="pl-v">RESPONSE_CLASSES</span>: <span class="pl-v">Final</span> <span class="pl-c1">=</span> {
        <span class="pl-v">MsgpackResponse</span>.<span class="pl-s1">media_type</span>: <span class="pl-v">MsgpackResponse</span>,
    }

    <span class="pl-k">def</span> <span class="pl-en">_get_multimedia_request_handler</span>(<span class="pl-s1">self</span>, <span class="pl-s1">mime_type</span>):
        <span class="pl-c"># Use custom response class or fall back on default self.response_class.</span>
        <span class="pl-s1">response_class</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-v">RESPONSE_CLASSES</span>.<span class="pl-en">get</span>(<span class="pl-s1">mime_type</span>, <span class="pl-s1">self</span>.<span class="pl-s1">response_class</span>)
        <span class="pl-c"># Use msgpack override encoder for msgpack responses.</span>
        <span class="pl-s1">custom_encoder</span> <span class="pl-c1">=</span> <span class="pl-s1">msgpack_encoder_override</span> <span class="pl-k">if</span> <span class="pl-s1">mime_type</span> <span class="pl-c1">==</span> <span class="pl-v">MSGPACK</span> <span class="pl-k">else</span> <span class="pl-c1">None</span>

        <span class="pl-k">return</span> <span class="pl-en">get_request_handler</span>(
            <span class="pl-s1">dependant</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">dependant</span>,
            <span class="pl-s1">body_field</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">body_field</span>,
            <span class="pl-s1">status_code</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">status_code</span>,
            <span class="pl-s1">response_class</span><span class="pl-c1">=</span><span class="pl-s1">response_class</span>,  <span class="pl-c"># Based on mime_type (see above)</span>
            <span class="pl-s1">response_field</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">secure_cloned_response_field</span>,
            <span class="pl-s1">response_model_include</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">response_model_include</span>,
            <span class="pl-s1">response_model_exclude</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">response_model_exclude</span>,
            <span class="pl-s1">response_model_by_alias</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">response_model_by_alias</span>,
            <span class="pl-s1">response_model_exclude_unset</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">response_model_exclude_unset</span>,
            <span class="pl-s1">response_model_exclude_defaults</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">response_model_exclude_defaults</span>,
            <span class="pl-s1">response_model_exclude_none</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">response_model_exclude_none</span>,
            <span class="pl-s1">dependency_overrides_provider</span><span class="pl-c1">=</span><span class="pl-s1">self</span>.<span class="pl-s1">dependency_overrides_provider</span>,
            <span class="pl-s1">custom_encoder</span><span class="pl-c1">=</span><span class="pl-s1">custom_encoder</span>,  <span class="pl-c"># Based on mime_type (see above)</span>
        )

    <span class="pl-k">def</span> <span class="pl-en">get_route_handler</span>(<span class="pl-s1">self</span>) <span class="pl-c1">-&gt;</span> <span class="pl-v">Callable</span>:
        <span class="pl-s">"""Overrides APIRoute.get_route_handler()"""</span>

        <span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">multimedia_route_handler</span>(<span class="pl-s1">request</span>: <span class="pl-v">Request</span>) <span class="pl-c1">-&gt;</span> <span class="pl-v">Response</span>:

            <span class="pl-s1">content_type_headers</span> <span class="pl-c1">=</span> <span class="pl-s1">request</span>.<span class="pl-s1">headers</span>.<span class="pl-en">get</span>(<span class="pl-s">"Content-Type"</span>)
            <span class="pl-k">try</span>:
                <span class="pl-s1">request_cls</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-v">REQUEST_CLASSES</span>[<span class="pl-s1">content_type_headers</span>]
                <span class="pl-s1">request</span> <span class="pl-c1">=</span> <span class="pl-en">request_cls</span>(<span class="pl-s1">request</span>.<span class="pl-s1">scope</span>, <span class="pl-s1">request</span>.<span class="pl-s1">receive</span>)
            <span class="pl-k">except</span> <span class="pl-v">KeyError</span>:
                <span class="pl-k">pass</span>  <span class="pl-c"># No handler for content_type, process request as-is.</span>

            <span class="pl-s1">accept_headers</span> <span class="pl-c1">=</span> <span class="pl-s1">request</span>.<span class="pl-s1">headers</span>.<span class="pl-en">get</span>(<span class="pl-s">"Accept"</span>)
            <span class="pl-s1">route_handler</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-en">_get_multimedia_request_handler</span>(<span class="pl-s1">accept_headers</span>)
            <span class="pl-k">return</span> <span class="pl-k">await</span> <span class="pl-en">route_handler</span>(<span class="pl-s1">request</span>)

        <span class="pl-k">return</span> <span class="pl-s1">multimedia_route_handler</span>


<span class="pl-k">class</span> <span class="pl-v">ModelConfig</span>:
    <span class="pl-s1">json_encoders</span> <span class="pl-c1">=</span> <span class="pl-s1">custom_json_encoder</span>
    <span class="pl-s1">validate_assignment</span> <span class="pl-c1">=</span> <span class="pl-c1">True</span>


<span class="pl-k">class</span> <span class="pl-v">ModelWithBytes</span>(<span class="pl-v">BaseModel</span>):
    <span class="pl-s1">text</span>: <span class="pl-s1">str</span>
    <span class="pl-s1">raw</span>: <span class="pl-v">Base64Bytes</span>

    <span class="pl-k">class</span> <span class="pl-v">Config</span>(<span class="pl-v">ModelConfig</span>):
        <span class="pl-k">pass</span>


<span class="pl-v">TEXT</span>: <span class="pl-v">Final</span> <span class="pl-c1">=</span><span class="pl-s">"text"</span>
<span class="pl-v">BYTES</span>: <span class="pl-v">Final</span> <span class="pl-c1">=</span> <span class="pl-s">b"<span class="pl-cce">\x16</span><span class="pl-cce">\r</span><span class="pl-cce">\xd4</span>)<span class="pl-cce">\x93</span>&gt;(<span class="pl-cce">\x04</span><span class="pl-cce">\x83</span><span class="pl-cce">\xcc</span><span class="pl-cce">\xc5</span><span class="pl-cce">\xd6</span>"</span>


<span class="pl-s1">test_dict</span> <span class="pl-c1">=</span> {
    <span class="pl-s">"text"</span>: <span class="pl-v">TEXT</span>,
    <span class="pl-s">"raw"</span>: <span class="pl-v">BYTES</span>,
}

<span class="pl-s1">base64_encoded_test_dict</span> <span class="pl-c1">=</span> {
    <span class="pl-s">"text"</span>: <span class="pl-v">TEXT</span>,
    <span class="pl-s">"raw"</span>: <span class="pl-en">base64_encode_as_str</span>(<span class="pl-v">BYTES</span>),
}


<span class="pl-s1">router</span> <span class="pl-c1">=</span> <span class="pl-v">APIRouter</span>(<span class="pl-s1">route_class</span><span class="pl-c1">=</span><span class="pl-v">MultimediaRouteMixin</span>)


<span class="pl-en">@<span class="pl-s1">router</span>.<span class="pl-en">post</span>(<span class="pl-s">""</span>)</span>
<span class="pl-k">def</span> <span class="pl-en">post_test_model</span>(<span class="pl-s1">body</span>: <span class="pl-v">ModelWithBytes</span>) <span class="pl-c1">-&gt;</span> <span class="pl-v">ModelWithBytes</span>:
    <span class="pl-k">assert</span> <span class="pl-s1">body</span> <span class="pl-c1">==</span> <span class="pl-v">ModelWithBytes</span>(<span class="pl-s1">text</span><span class="pl-c1">=</span><span class="pl-v">TEXT</span>, <span class="pl-s1">raw</span><span class="pl-c1">=</span><span class="pl-v">BYTES</span>)
    <span class="pl-k">assert</span> <span class="pl-v">ModelConfig</span>.<span class="pl-s1">json_encoders</span>[<span class="pl-v">Base64Bytes</span>] <span class="pl-c1">is</span> <span class="pl-s1">base64_encode_as_str</span>
    <span class="pl-c"># Verify jsonable_encoder did not mutate body</span>
    <span class="pl-c"># TODO: assert Base64Bytes not in body.__config__.json_encoders</span>
    <span class="pl-k">return</span> <span class="pl-s1">body</span>


<span class="pl-v">ENDPOINT_PATH</span>: <span class="pl-v">Final</span> <span class="pl-c1">=</span> <span class="pl-s">"/test_multimedia"</span>

<span class="pl-s1">app</span>.<span class="pl-en">include_router</span>(<span class="pl-s1">router</span><span class="pl-c1">=</span><span class="pl-s1">router</span>, <span class="pl-s1">prefix</span><span class="pl-c1">=</span><span class="pl-v">ENDPOINT_PATH</span>)

<span class="pl-s1">client</span> <span class="pl-c1">=</span> <span class="pl-v">TestClient</span>(<span class="pl-s1">app</span>)


<span class="pl-k">def</span> <span class="pl-en">test_multimedia_route</span>():
    <span class="pl-s">"""Test multimedia "middleware" (route mixin) for a simple payload</span>
<span class="pl-s">    that includes raw bytes for two combinations of  'Accept' and</span>
<span class="pl-s">    'Content-Type' HTTP headers."""</span>

    <span class="pl-c"># Test JSON-to-JSON POST</span>
    <span class="pl-k">for</span> <span class="pl-s1">headers</span> <span class="pl-c1">in</span> (
        {},
        {<span class="pl-v">ACCEPT</span>: <span class="pl-v">JSON</span>},
        {<span class="pl-v">CONTENT_TYPE</span>: <span class="pl-v">JSON</span>},
        {<span class="pl-v">ACCEPT</span>: <span class="pl-v">JSON</span>, <span class="pl-v">CONTENT_TYPE</span>: <span class="pl-v">JSON</span>},
    ):
        <span class="pl-s1">resp</span> <span class="pl-c1">=</span> <span class="pl-s1">client</span>.<span class="pl-en">post</span>(
            <span class="pl-v">ENDPOINT_PATH</span>,
            <span class="pl-s1">json</span><span class="pl-c1">=</span><span class="pl-s1">base64_encoded_test_dict</span>,
            <span class="pl-s1">headers</span><span class="pl-c1">=</span><span class="pl-s1">headers</span>,
        )
        <span class="pl-k">assert</span> <span class="pl-s1">resp</span>.<span class="pl-s1">ok</span>
        <span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-s1">resp</span>.<span class="pl-en">json</span>()
        <span class="pl-k">assert</span> <span class="pl-s1">resp</span>.<span class="pl-s1">status_code</span> <span class="pl-c1">==</span> <span class="pl-s1">status</span>.<span class="pl-v">HTTP_200_OK</span>
        <span class="pl-k">assert</span> <span class="pl-s1">result</span> <span class="pl-c1">==</span> <span class="pl-s1">base64_encoded_test_dict</span>

    <span class="pl-c"># Test JSON-to-msgpack POST</span>
    <span class="pl-k">for</span> <span class="pl-s1">headers</span> <span class="pl-c1">in</span> (
        {<span class="pl-v">ACCEPT</span>: <span class="pl-v">MSGPACK</span>},
        {<span class="pl-v">ACCEPT</span>: <span class="pl-v">MSGPACK</span>, <span class="pl-v">CONTENT_TYPE</span>: <span class="pl-v">JSON</span>},
    ):
        <span class="pl-s1">resp</span> <span class="pl-c1">=</span> <span class="pl-s1">client</span>.<span class="pl-en">post</span>(
            <span class="pl-v">ENDPOINT_PATH</span>,
            <span class="pl-s1">headers</span><span class="pl-c1">=</span><span class="pl-s1">headers</span>,
            <span class="pl-s1">json</span><span class="pl-c1">=</span><span class="pl-s1">base64_encoded_test_dict</span>,
        )
        <span class="pl-k">assert</span> <span class="pl-s1">resp</span>.<span class="pl-s1">ok</span>
        <span class="pl-k">assert</span> <span class="pl-s1">resp</span>.<span class="pl-s1">status_code</span> <span class="pl-c1">==</span> <span class="pl-s1">status</span>.<span class="pl-v">HTTP_200_OK</span>
        <span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-s1">msgpack</span>.<span class="pl-en">unpackb</span>(<span class="pl-s1">resp</span>.<span class="pl-s1">content</span>)
        <span class="pl-k">assert</span> <span class="pl-s1">result</span> <span class="pl-c1">==</span> <span class="pl-s1">test_dict</span>

    <span class="pl-c"># Test msgpack-to-JSON POST</span>
    <span class="pl-k">for</span> <span class="pl-s1">headers</span> <span class="pl-c1">in</span> (
        {<span class="pl-v">CONTENT_TYPE</span>: <span class="pl-v">MSGPACK</span>},
        {<span class="pl-v">ACCEPT</span>: <span class="pl-v">JSON</span>, <span class="pl-v">CONTENT_TYPE</span>: <span class="pl-v">MSGPACK</span>},
    ):
        <span class="pl-s1">resp</span> <span class="pl-c1">=</span> <span class="pl-s1">client</span>.<span class="pl-en">post</span>(
            <span class="pl-v">ENDPOINT_PATH</span>,
            <span class="pl-s1">headers</span><span class="pl-c1">=</span><span class="pl-s1">headers</span>,
            <span class="pl-s1">data</span><span class="pl-c1">=</span><span class="pl-s1">msgpack</span>.<span class="pl-en">packb</span>(<span class="pl-s1">test_dict</span>),
        )
        <span class="pl-k">assert</span> <span class="pl-s1">resp</span>.<span class="pl-s1">ok</span>
        <span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-s1">resp</span>.<span class="pl-en">json</span>()
        <span class="pl-k">assert</span> <span class="pl-s1">resp</span>.<span class="pl-s1">status_code</span> <span class="pl-c1">==</span> <span class="pl-s1">status</span>.<span class="pl-v">HTTP_200_OK</span>
        <span class="pl-k">assert</span> <span class="pl-s1">result</span> <span class="pl-c1">==</span> <span class="pl-s1">base64_encoded_test_dict</span>

    <span class="pl-c"># Test msgpack-to-msgpack POST</span>
    <span class="pl-k">for</span> <span class="pl-s1">headers</span> <span class="pl-c1">in</span> (
        {<span class="pl-v">ACCEPT</span>: <span class="pl-v">MSGPACK</span>, <span class="pl-v">CONTENT_TYPE</span>: <span class="pl-v">MSGPACK</span>},
    ):
        <span class="pl-s1">resp</span> <span class="pl-c1">=</span> <span class="pl-s1">client</span>.<span class="pl-en">post</span>(
            <span class="pl-v">ENDPOINT_PATH</span>,
            <span class="pl-s1">headers</span><span class="pl-c1">=</span><span class="pl-s1">headers</span>,
            <span class="pl-s1">data</span><span class="pl-c1">=</span><span class="pl-s1">msgpack</span>.<span class="pl-en">packb</span>(<span class="pl-s1">test_dict</span>),
        )
        <span class="pl-k">assert</span> <span class="pl-s1">resp</span>.<span class="pl-s1">ok</span>
        <span class="pl-k">assert</span> <span class="pl-s1">resp</span>.<span class="pl-s1">status_code</span> <span class="pl-c1">==</span> <span class="pl-s1">status</span>.<span class="pl-v">HTTP_200_OK</span>
        <span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-s1">msgpack</span>.<span class="pl-en">unpackb</span>(<span class="pl-s1">resp</span>.<span class="pl-s1">content</span>)
        <span class="pl-k">assert</span> <span class="pl-s1">result</span> <span class="pl-c1">==</span> <span class="pl-s1">test_dict</span>

    <span class="pl-c"># Test for error when sending JSON but expecting msgpack</span>
    <span class="pl-s1">resp</span> <span class="pl-c1">=</span> <span class="pl-s1">client</span>.<span class="pl-en">post</span>(
        <span class="pl-v">ENDPOINT_PATH</span>,
        <span class="pl-s1">headers</span><span class="pl-c1">=</span>{<span class="pl-v">CONTENT_TYPE</span>: <span class="pl-v">MSGPACK</span>},
        <span class="pl-s1">json</span><span class="pl-c1">=</span><span class="pl-s1">base64_encoded_test_dict</span>,
    )
    <span class="pl-k">assert</span> <span class="pl-c1">not</span> <span class="pl-s1">resp</span>.<span class="pl-s1">ok</span>
    <span class="pl-k">assert</span> <span class="pl-s1">resp</span>.<span class="pl-s1">status_code</span> <span class="pl-c1">==</span> <span class="pl-s1">status</span>.<span class="pl-v">HTTP_400_BAD_REQUEST</span>

    <span class="pl-c"># Test for error when sending msgpack but expecting JSON</span>
    <span class="pl-s1">resp</span> <span class="pl-c1">=</span> <span class="pl-s1">client</span>.<span class="pl-en">post</span>(
        <span class="pl-v">ENDPOINT_PATH</span>,
        <span class="pl-s1">headers</span><span class="pl-c1">=</span>{<span class="pl-v">CONTENT_TYPE</span>: <span class="pl-v">JSON</span>},
        <span class="pl-s1">data</span><span class="pl-c1">=</span><span class="pl-s1">msgpack</span>.<span class="pl-en">packb</span>(<span class="pl-s1">test_dict</span>),
    )
    <span class="pl-k">assert</span> <span class="pl-c1">not</span> <span class="pl-s1">resp</span>.<span class="pl-s1">ok</span>
    <span class="pl-k">assert</span> <span class="pl-s1">resp</span>.<span class="pl-s1">status_code</span> <span class="pl-c1">==</span> <span class="pl-s1">status</span>.<span class="pl-v">HTTP_400_BAD_REQUEST</span>


<span class="pl-c"># Restore pre-test state</span>
<span class="pl-s1">fastapi</span>.<span class="pl-s1">encoders</span>.<span class="pl-s1">catchall_encoder</span> <span class="pl-c1">=</span> <span class="pl-s1">_catchall_encoder_saved</span></pre></div>
<h3 dir="auto">Alternatives</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">Operating System</h3>
<p dir="auto">Linux</p>
<h3 dir="auto">Operating System Details</h3>
<p dir="auto">Ubuntu 20.04.5 LTS</p>
<h3 dir="auto">FastAPI Version</h3>
<p dir="auto">0.83.0</p>
<h3 dir="auto">Python Version</h3>
<p dir="auto">3.8.12</p>
<h3 dir="auto">Additional Context</h3>
<ul dir="auto">
<li>closes <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1373250991" data-permission-text="Title is private" data-url="https://github.com/tiangolo/fastapi/issues/5389" data-hovercard-type="issue" data-hovercard-url="/tiangolo/fastapi/issues/5389/hovercard" href="https://github.com/tiangolo/fastapi/issues/5389">#5389</a></li>
<li>closes <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1373268307" data-permission-text="Title is private" data-url="https://github.com/tiangolo/fastapi/issues/5390" data-hovercard-type="pull_request" data-hovercard-url="/tiangolo/fastapi/pull/5390/hovercard" href="https://github.com/tiangolo/fastapi/pull/5390">#5390</a></li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="492250076" data-permission-text="Title is private" data-url="https://github.com/tiangolo/fastapi/issues/521" data-hovercard-type="issue" data-hovercard-url="/tiangolo/fastapi/issues/521/hovercard" href="https://github.com/tiangolo/fastapi/issues/521">#521</a></li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="712790049" data-permission-text="Title is private" data-url="https://github.com/tiangolo/fastapi/issues/2117" data-hovercard-type="issue" data-hovercard-url="/tiangolo/fastapi/issues/2117/hovercard" href="https://github.com/tiangolo/fastapi/issues/2117">#2117</a></li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="823051186" data-permission-text="Title is private" data-url="https://github.com/tiangolo/fastapi/issues/2901" data-hovercard-type="issue" data-hovercard-url="/tiangolo/fastapi/issues/2901/hovercard" href="https://github.com/tiangolo/fastapi/issues/2901">#2901</a></li>
</ul>