Skip to content
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

use simplejson to allow NaN/inf/-inf in JSON response #374

Merged
merged 2 commits into from
Sep 23, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 6 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
# Release Notes

## 0.3.10 (TBD)
## 0.3.10 (2021-09-23)

### titiler.core

- add custom JSONResponse using [simplejson](https://simplejson.readthedocs.io/en/latest/) to allow NaN/inf/-inf values

### titiler.application

- switch to `starlette_cramjam` compression middleware (ref: https://github.com/developmentseed/titiler/issues/369)
- use `titiler.core.resources.responses.JSONResponse` as default application response.

## 0.3.9 (2021-09-07)

Expand Down
Binary file not shown.
20 changes: 20 additions & 0 deletions src/titiler/application/tests/routes/test_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,23 @@ def test_validate_cog(app, url):
response = app.get(f"/cog/validate?url={os.path.join(DATA_DIR, 'cog.tif')}")
assert response.status_code == 200
assert response.json()["COG"]


@patch("rio_tiler.io.cogeo.rasterio")
def test_info_nan(rio, app):
"""test /info endpoint."""
rio.open = mock_rasterio_open

response = app.get("/cog/info?url=https://myurl.com/cog_with_nan.tif")
assert response.status_code == 200
body = response.json()
assert body["dtype"] == "float32"
assert body["nodata_type"] == "Nodata"

response = app.get("/cog/info.geojson?url=https://myurl.com/cog_with_nan.tif")
assert response.status_code == 200
assert response.headers["content-type"] == "application/geo+json"
body = response.json()
assert body["geometry"]
assert body["properties"]["nodata_type"] == "Nodata"
assert body["properties"]["nodata_value"] is None
2 changes: 2 additions & 0 deletions src/titiler/application/titiler/application/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
LowerCaseQueryStringMiddleware,
TotalTimeMiddleware,
)
from titiler.core.resources.responses import JSONResponse
from titiler.mosaic.errors import MOSAIC_STATUS_CODES

from fastapi import FastAPI
Expand All @@ -33,6 +34,7 @@
description="A lightweight Cloud Optimized GeoTIFF tile server",
version=titiler_version,
root_path=api_settings.root_path,
default_response_class=JSONResponse,
)

if not api_settings.disable_cog:
Expand Down
1 change: 1 addition & 0 deletions src/titiler/core/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"pydantic",
"rasterio",
"rio-tiler>=2.1,<2.2",
"simplejson",
# Additional requirements for python 3.6
"async_exit_stack>=1.0.1,<2.0.0;python_version<'3.7'",
"async_generator>=1.10,<2.0.0;python_version<'3.7'",
Expand Down
26 changes: 24 additions & 2 deletions src/titiler/core/titiler/core/resources/responses.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
"""Common response models."""

from starlette.responses import JSONResponse, Response
from typing import Any

import simplejson as json

class XMLResponse(Response):
from starlette import responses


class XMLResponse(responses.Response):
"""XML Response"""

media_type = "application/xml"


class JSONResponse(responses.JSONResponse):
"""Custom JSON Response."""

def render(self, content: Any) -> bytes:
"""Render JSON.

Same defaults as starlette.responses.JSONResponse.render but allow NaN to be replaced by null using simplejson
"""
return json.dumps(
content,
ensure_ascii=False,
allow_nan=False,
indent=None,
ignore_nan=True,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

separators=(",", ":"),
).encode("utf-8")


class GeoJSONResponse(JSONResponse):
"""GeoJSON Response"""

Expand Down