mirror of
https://github.com/simonw/datasette.git
synced 2026-10-21 00:36:59 +02:00
Merge a228deff90 into cf113a5985
This commit is contained in:
commit
60a5413dd2
3 changed files with 52 additions and 9 deletions
|
|
@ -55,14 +55,19 @@ def handle_exception(datasette, request, exception):
|
|||
headers = {}
|
||||
if datasette.cors:
|
||||
add_cors_headers(headers)
|
||||
if request.path.split("?")[0].endswith(".json"):
|
||||
body = dict(info)
|
||||
body.update(error_body(plain_message or message, status))
|
||||
return Response.json(body, status=status, headers=headers)
|
||||
if request.path.split("?")[0].endswith(".csv"):
|
||||
path = request.path.split("?")[0]
|
||||
if path.endswith(".csv"):
|
||||
return Response.text(
|
||||
plain_message or message, status=status, headers=headers
|
||||
)
|
||||
if (
|
||||
path.endswith(".json")
|
||||
or "application/json" in (request.headers.get("accept") or "")
|
||||
or request.headers.get("content-type") == "application/json"
|
||||
):
|
||||
body = dict(info)
|
||||
body.update(error_body(plain_message or message, status))
|
||||
return Response.json(body, status=status, headers=headers)
|
||||
info.update(
|
||||
{
|
||||
"ok": False,
|
||||
|
|
|
|||
|
|
@ -129,10 +129,11 @@ Some endpoints add extra context keys. For example, a SQL error from a
|
|||
``"rows"`` and ``"truncated"`` keys of the response it was unable to
|
||||
produce.
|
||||
|
||||
Permission errors use the same format: a request that fails a permission
|
||||
check receives a ``403`` with this JSON error body when the URL ends in
|
||||
``.json`` or the request sends an ``Accept: application/json`` or
|
||||
``Content-Type: application/json`` header.
|
||||
Errors handled by Datasette's exception and permission handlers use this
|
||||
format when the URL ends in ``.json`` or the request sends an
|
||||
``Accept: application/json`` or ``Content-Type: application/json`` header.
|
||||
Without one of these signals, an error on an HTML page is rendered as HTML.
|
||||
Errors on explicit ``.csv`` URLs remain plain text, regardless of headers.
|
||||
|
||||
.. _json_api_custom_sql:
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,43 @@ async def test_not_found_error_shape(ds_client):
|
|||
assert_canonical_error(response, 404)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"headers",
|
||||
(
|
||||
{"Accept": "application/json"},
|
||||
{"Content-Type": "application/json"},
|
||||
),
|
||||
)
|
||||
async def test_not_found_error_shape_with_json_request_headers(ds_client, headers):
|
||||
response = await ds_client.get("/fixtures/no_such_table", headers=headers)
|
||||
assert_canonical_error(response, 404)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_not_found_without_json_request_headers_returns_html(ds_client):
|
||||
response = await ds_client.get("/fixtures/no_such_table")
|
||||
assert response.status_code == 404
|
||||
assert response.headers["content-type"].startswith("text/html")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_csv_error_keeps_text_format_with_json_accept_header(ds_client):
|
||||
response = await ds_client.get(
|
||||
"/fixtures/no_such_table.csv", headers={"Accept": "application/json"}
|
||||
)
|
||||
assert response.status_code == 404
|
||||
assert response.headers["content-type"].startswith("text/plain")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_write_api_missing_database_error_shape(ds_client):
|
||||
response = await ds_client.post(
|
||||
"/no_such/-/create", json={}, headers={"Content-Type": "application/json"}
|
||||
)
|
||||
assert_canonical_error(response, 404)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_datasette_error_with_title_omits_title_key(ds_client):
|
||||
# DatasetteError(title="Invalid SQL") previously leaked a "title" key
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue