question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[QUESTION] Msgpack/JSON request/response without middleware

See original GitHub issue

First check

  • I used the GitHub search to find a similar issue and didn’t find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google “How to X in FastAPI” and didn’t find any information.

Description

How can I allow msgpack or JSON encoding in requests/responses without the middleware approach based on Content-Type and Accept headers. See the middleware approach here: https://github.com/tiangolo/fastapi/issues/521

We use msgpack because it’s smaller as mentioned in the previous issue, but also because numerical data can be encoded/decoded much faster (1,000x+) with msgpack, (e.g., NumPy, Pandas, PyTorch, …). In addition, general access to raw byte returns is beneficial without having have to encode/decode Python strings. Basing the encoding off Content-Type and Accept headers is beneficial for clients who do not want to bother with msgpack.

Additional context

My current solution is as follows.

Step 1

Prevent FastAPI from automatically serializing NumPy arrays and other binary objects in its jsonable_encoder function:

import numpy as np
from pydantic.json import ENCODERS_BY_TYPE

# Warnings and exclamation marks as this is a bit dangerous and Pydantic global...
ENCODERS_BY_TYPE[np.ndarray] = lambda x: x
...

Step 2

Custom msgpack encoders/decoders:

def custom_serializer(data: Any) ->bytes:

    def array_serialize(obj: Any) -> Any:
        # We can provide real msgpack here, but close enough for demonstration
        if isinstance(obj, np.ndarray):
             return np.ascontiguousarray(obj).tobytes()
        return obj

    return msgpack.loads(blob, object_hook=msgpack_decode, raw=False)

def custom_deserialize():
...

Step 3

Allowing msgpack requests without running through JSON can be worked as in #521 with the following:

class MsgpackRequest(Request):
    async def json(self) -> Any:
        if "application/x-msgpack" in self.headers.getlist("Content-Type"):
            self._json = custom_deserialize(self._body)
        return await super().json()

Step 4

Responses are the trickier part without running through JSON as in #521. You can return a custom response class for every route, but that doesn’t allow you to parametrize this based off the Accept header as the information never exists within the Response classes [1]. My current solution is to make a new APIRoute class which replaces this function which works fine, but I worry is a bit brittle.

Questions:

  1. Is there a simpler way to accomplish the above?
  2. Is [1] patchable where we can pass through the headers to the Response class which can then determine its own content serialization (solves step 4)?
  3. Is there room for strategic PRs which make other serialization formats beyond JSON easier?

[1] This may not be fully true. Looking at it, I think Starlette allows this, but FastAPI simply does not pass this through.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:11
  • Comments:5

github_iconTop GitHub Comments

5reactions
estancommented, Feb 6, 2022

@tiangolo Hey, suspect you are super-busy, but any input on this? It seems @dgasmith was, at least at one point, willing to make a PR for this, if just given some input on the preferred approach (https://github.com/tiangolo/fastapi/issues/521#issuecomment-658291782). It would be absolutely great if plugging in different serializations (MsgPack, CBOR, …), without the CPU overhead of internal JSON serialization, was more streamlined.

4reactions
estancommented, Oct 22, 2020

Thanks for filing this @dgasmith. Like my comment on #521 said, we are in the same boat as you. Working with medium to large sized numerical data APIs. Would love for one of the maintainers to chime in either there or here.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Return every request as plain json Laravel using Middleware
I checked it, it applies middleware on every request so that is not a problem. Why is this happening and shouldn't it convert...
Read more >
Chapter 2 - Sockets and Patterns - ZeroMQ guide
It turns “Message Oriented Middleware”, a phrase guaranteed to send the whole room off to Catatonia, into “Extra Spicy Sockets!
Read more >
The ZeroMQ Guide - for C Developers
ØMQ (also known as ZeroMQ, ØMQ, or zmq) looks like an embeddable networking library but acts like a concurrency framework. It gives you...
Read more >
MessagePack: It's like JSON. but fast and small.
If you want to use msgpack at OCaml, you need not do this section. This section for user intrested in formal verification. You...
Read more >
ZMQ guider_凌风探梅的博客-CSDN博客
We assume you care about scale, because ØMQ solves that problem above all ... The physics of software is not algorithms, data structures,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found