mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
rel=alternate JSON for queries and database pages, closes #1620
This commit is contained in:
parent
3ef47a0896
commit
b72b2423c7
7 changed files with 91 additions and 31 deletions
|
|
@ -3,7 +3,8 @@
|
|||
{% block title %}{{ database }}{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
{{ super() }}
|
||||
{{- super() -}}
|
||||
<link rel="alternate" type="application/json+datasette" href="{{ alternate_url_json }}">
|
||||
{% include "_codemirror.html" %}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
{% block title %}{{ database }}{% if query and query.sql %}: {{ query.sql }}{% endif %}{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
{{ super() }}
|
||||
{{- super() -}}
|
||||
<link rel="alternate" type="application/json+datasette" href="{{ alternate_url_json }}">
|
||||
{% if columns %}
|
||||
<style>
|
||||
@media only screen and (max-width: 576px) {
|
||||
|
|
|
|||
|
|
@ -123,6 +123,10 @@ class DatabaseView(DataView):
|
|||
|
||||
attached_databases = [d.name for d in await db.attached_databases()]
|
||||
|
||||
alternate_url_json = self.ds.absolute_url(
|
||||
request,
|
||||
self.ds.urls.path(path_with_format(request=request, format="json")),
|
||||
)
|
||||
return (
|
||||
{
|
||||
"database": database,
|
||||
|
|
@ -140,6 +144,7 @@ class DatabaseView(DataView):
|
|||
),
|
||||
},
|
||||
{
|
||||
"alternate_url_json": alternate_url_json,
|
||||
"database_actions": database_actions,
|
||||
"show_hidden": request.args.get("_show_hidden"),
|
||||
"editable": True,
|
||||
|
|
@ -148,6 +153,11 @@ class DatabaseView(DataView):
|
|||
and not db.is_mutable
|
||||
and not db.is_memory,
|
||||
"attached_databases": attached_databases,
|
||||
"_extra_headers": {
|
||||
"Link": '{}; rel="alternate"; type="application/json+datasette"'.format(
|
||||
alternate_url_json
|
||||
)
|
||||
},
|
||||
},
|
||||
(f"database-{to_css_class(database)}.html", "database.html"),
|
||||
)
|
||||
|
|
@ -308,7 +318,14 @@ class QueryView(DataView):
|
|||
else:
|
||||
|
||||
async def extra_template():
|
||||
alternate_url_json = self.ds.absolute_url(
|
||||
request,
|
||||
self.ds.urls.path(
|
||||
path_with_format(request=request, format="json")
|
||||
),
|
||||
)
|
||||
return {
|
||||
"alternate_url_json": alternate_url_json,
|
||||
"request": request,
|
||||
"path_with_added_args": path_with_added_args,
|
||||
"path_with_removed_args": path_with_removed_args,
|
||||
|
|
@ -316,6 +333,11 @@ class QueryView(DataView):
|
|||
"canned_query": canned_query,
|
||||
"success_message": request.args.get("_success") or "",
|
||||
"canned_write": True,
|
||||
"_extra_headers": {
|
||||
"Link": '{}; rel="alternate"; type="application/json+datasette"'.format(
|
||||
alternate_url_json
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -448,7 +470,12 @@ class QueryView(DataView):
|
|||
show_hide_link = path_with_added_args(request, {"_hide_sql": 1})
|
||||
show_hide_text = "hide"
|
||||
hide_sql = show_hide_text == "show"
|
||||
alternate_url_json = self.ds.absolute_url(
|
||||
request,
|
||||
self.ds.urls.path(path_with_format(request=request, format="json")),
|
||||
)
|
||||
return {
|
||||
"alternate_url_json": alternate_url_json,
|
||||
"display_rows": display_rows,
|
||||
"custom_sql": True,
|
||||
"named_parameter_values": named_parameter_values,
|
||||
|
|
@ -462,6 +489,11 @@ class QueryView(DataView):
|
|||
"show_hide_text": show_hide_text,
|
||||
"show_hide_hidden": markupsafe.Markup(show_hide_hidden),
|
||||
"hide_sql": hide_sql,
|
||||
"_extra_headers": {
|
||||
"Link": '{}; rel="alternate"; type="application/json+datasette"'.format(
|
||||
alternate_url_json
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -442,7 +442,7 @@ in ``metadata.json`` - see :ref:`label_columns`.
|
|||
Discovering the JSON for a page
|
||||
-------------------------------
|
||||
|
||||
The :ref:`table <TableView>` and :ref:`row <RowView>` HTML pages both provide a mechanism for discovering their JSON equivalents using the HTML ``link`` mechanism.
|
||||
The :ref:`database <DatabaseView>`, :ref:`table <TableView>`, :ref:`custom/canned query <sql>` and :ref:`row <RowView>` HTML pages all provide a mechanism for discovering their JSON equivalents using the HTML ``link`` mechanism.
|
||||
|
||||
You can find this near the top of those pages, looking like this:
|
||||
|
||||
|
|
|
|||
|
|
@ -364,3 +364,12 @@ def test_canned_write_custom_template(canned_write_client):
|
|||
in response.text
|
||||
)
|
||||
assert "!!!CUSTOM_UPDATE_NAME_TEMPLATE!!!" in response.text
|
||||
# And test for link rel=alternate while we're here:
|
||||
assert (
|
||||
'<link rel="alternate" type="application/json+datasette" href="http://localhost/data/update_name.json">'
|
||||
in response.text
|
||||
)
|
||||
assert (
|
||||
response.headers["link"]
|
||||
== 'http://localhost/data/update_name.json; rel="alternate"; type="application/json+datasette"'
|
||||
)
|
||||
|
|
|
|||
|
|
@ -870,3 +870,48 @@ def test_trace_correctly_escaped(app_client):
|
|||
response = app_client.get("/fixtures?sql=select+'<h1>Hello'&_trace=1")
|
||||
assert "select '<h1>Hello" not in response.text
|
||||
assert "select '<h1>Hello" in response.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"path,expected",
|
||||
(
|
||||
# Table page
|
||||
(
|
||||
"/fixtures/table%2Fwith%2Fslashes.csv",
|
||||
"http://localhost/fixtures/table%2Fwith%2Fslashes.csv?_format=json",
|
||||
),
|
||||
("/fixtures/facetable", "http://localhost/fixtures/facetable.json"),
|
||||
# Row page
|
||||
(
|
||||
"/fixtures/no_primary_key/1",
|
||||
"http://localhost/fixtures/no_primary_key/1.json",
|
||||
),
|
||||
# Database index page
|
||||
(
|
||||
"/fixtures",
|
||||
"http://localhost/fixtures.json",
|
||||
),
|
||||
# Custom query page
|
||||
(
|
||||
"/fixtures?sql=select+*+from+facetable",
|
||||
"http://localhost/fixtures.json?sql=select+*+from+facetable",
|
||||
),
|
||||
# Canned query page
|
||||
(
|
||||
"/fixtures/neighborhood_search?text=town",
|
||||
"http://localhost/fixtures/neighborhood_search.json?text=town",
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_alternate_url_json(app_client, path, expected):
|
||||
response = app_client.get(path)
|
||||
link = response.headers["link"]
|
||||
assert link == '{}; rel="alternate"; type="application/json+datasette"'.format(
|
||||
expected
|
||||
)
|
||||
assert (
|
||||
'<link rel="alternate" type="application/json+datasette" href="{}">'.format(
|
||||
expected
|
||||
)
|
||||
in response.text
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1069,31 +1069,3 @@ def test_table_page_title(app_client, path, expected):
|
|||
response = app_client.get(path)
|
||||
title = Soup(response.text, "html.parser").find("title").text
|
||||
assert title == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"path,expected",
|
||||
(
|
||||
(
|
||||
"/fixtures/table%2Fwith%2Fslashes.csv",
|
||||
"http://localhost/fixtures/table%2Fwith%2Fslashes.csv?_format=json",
|
||||
),
|
||||
("/fixtures/facetable", "http://localhost/fixtures/facetable.json"),
|
||||
(
|
||||
"/fixtures/no_primary_key/1",
|
||||
"http://localhost/fixtures/no_primary_key/1.json",
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_alternate_url_json(app_client, path, expected):
|
||||
response = app_client.get(path)
|
||||
link = response.headers["link"]
|
||||
assert link == '{}; rel="alternate"; type="application/json+datasette"'.format(
|
||||
expected
|
||||
)
|
||||
assert (
|
||||
'<link rel="alternate" type="application/json+datasette" href="{}">'.format(
|
||||
expected
|
||||
)
|
||||
in response.text
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue