Browse Source

Merge 3ea368646e into e6d09027e5

pull/13760/merge
Kamran Pulatov 1 day ago
committed by GitHub
parent
commit
43565ec34e
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      .gitignore
  2. 45
      fastapi/responses.py
  3. 4
      pyproject.toml
  4. 20
      tests/test_bson_response_class.py
  5. 26
      tests/test_bsonjs_response_class.py

4
.gitignore

@ -28,3 +28,7 @@ archive.zip
# macOS
.DS_Store
# Pdm additional files
.pdm-python
pdm.lock

45
fastapi/responses.py

@ -1,3 +1,4 @@
import json
from typing import Any
from starlette.responses import FileResponse as FileResponse # noqa
@ -20,6 +21,18 @@ except ImportError: # pragma: nocover
orjson = None # type: ignore
try:
import bson # type: ignore[import-untyped]
except ImportError: # pragma: nocover
bson = None
try:
import bsonjs # type: ignore
except ImportError: # pragma: nocover
bsonjs = None
class UJSONResponse(JSONResponse):
"""
JSON response using the high-performance ujson library to serialize data to JSON.
@ -46,3 +59,35 @@ class ORJSONResponse(JSONResponse):
return orjson.dumps(
content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY
)
class BSONResponse(Response):
"""
BSON response using the current Python bson library for data serialization.
Note: This is a temporary solution. Soon, a custom Rust wrapper will be implemented for BSON serialization/deserialization to improve performance and reliability.
Read more about it in the
[FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).
"""
media_type = "application/bson"
def render(self, content: Any) -> Any:
assert bson is not None, "bson must be installed to use BSONResponse"
return bson.dumps(content)
class BSONJSResponse(BSONResponse):
"""
BSON response using the C-backed python-bsonjs library to serialize BSON
Read more about it in the
[FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).
"""
media_type = "application/bson"
def render(self, content: Any) -> Any:
assert bsonjs is not None, "bsonjs must be installed to use BSONJSResponse"
return bsonjs.loads(json.dumps(content))

4
pyproject.toml

@ -111,6 +111,10 @@ all = [
"ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0",
# For ORJSONResponse
"orjson >=3.2.1",
# For BSONResponse
"bson >=0.5.10",
# For BSONJSResponse
"python-bsonjs >=0.6.0; python_version >= '3.9'",
# To validate email fields
"email-validator >=2.0.0",
# Uvicorn with uvloop

20
tests/test_bson_response_class.py

@ -0,0 +1,20 @@
import bson
from fastapi import FastAPI
from fastapi.responses import BSONResponse
from fastapi.testclient import TestClient
app = FastAPI(default_response_class=BSONResponse)
@app.get("/bson_keys")
def get_bson_serialized_data():
return {"key": "Hello World", 1: 1}
client = TestClient(app)
def test_bson_serialized_data():
with client:
response = client.get("/bson_keys")
assert response.content == bson.dumps({"key": "Hello World", 1: 1})

26
tests/test_bsonjs_response_class.py

@ -0,0 +1,26 @@
import json
import sys
import pytest
@pytest.mark.skipif(
sys.version_info < (3, 9), reason="requires minimum python3.9 or higher"
)
def test_bsonjs_serialized_data():
import bsonjs
from fastapi import FastAPI
from fastapi.responses import BSONJSResponse
from fastapi.testclient import TestClient
app = FastAPI(default_response_class=BSONJSResponse)
@app.get("/bsonjs_keys")
def get_bsonjs_serialized_data():
return {"key": "Hello World"}
client = TestClient(app)
with client:
response = client.get("/bsonjs_keys")
assert response.content == bsonjs.loads(json.dumps({"key": "Hello World"}))
Loading…
Cancel
Save