kopia lustrzana https://github.com/simonw/datasette
Example links for API explorer, closes #1871
rodzic
c603faac5b
commit
db796771e2
|
@ -22,7 +22,7 @@
|
|||
<form method="get" id="api-explorer-get" style="margin-top: 0.7em">
|
||||
<div>
|
||||
<label for="path">API path:</label>
|
||||
<input type="text" id="path" name="path" value="/data/docs.json" style="width: 60%">
|
||||
<input type="text" id="path" name="path" style="width: 60%">
|
||||
<input type="submit" value="GET">
|
||||
</div>
|
||||
</form>
|
||||
|
@ -32,7 +32,7 @@
|
|||
<form method="post" id="api-explorer-post" style="margin-top: 0.7em">
|
||||
<div>
|
||||
<label for="path">API path:</label>
|
||||
<input type="text" id="path" name="path" value="/data/docs/-/insert" style="width: 60%">
|
||||
<input type="text" id="path" name="path" style="width: 60%">
|
||||
</div>
|
||||
<div style="margin: 0.5em 0">
|
||||
<label for="apiJson" style="vertical-align: top">JSON:</label>
|
||||
|
@ -65,8 +65,11 @@ var getForm = document.getElementById('api-explorer-get');
|
|||
var output = document.getElementById('output');
|
||||
var errorList = output.querySelector('.errors');
|
||||
|
||||
// On first load, populate forms from # in URL, if present
|
||||
// On first load or fragment change populate forms from # in URL, if present
|
||||
if (window.location.hash) {
|
||||
onFragmentChange();
|
||||
}
|
||||
function onFragmentChange() {
|
||||
var hash = window.location.hash.slice(1);
|
||||
// Treat hash as a foo=bar string and parse it:
|
||||
var params = new URLSearchParams(hash);
|
||||
|
@ -82,6 +85,11 @@ if (window.location.hash) {
|
|||
postForm.querySelector('textarea[name="json"]').value = params.get('json');
|
||||
}
|
||||
}
|
||||
window.addEventListener('hashchange', () => {
|
||||
onFragmentChange();
|
||||
// Animate scroll to top of page
|
||||
window.scrollTo({top: 0, behavior: 'smooth'});
|
||||
});
|
||||
|
||||
// Cause GET and POST regions to toggle each other
|
||||
var getDetails = getForm.closest('details');
|
||||
|
@ -171,4 +179,27 @@ postForm.addEventListener("submit", (ev) => {
|
|||
});
|
||||
</script>
|
||||
|
||||
{% if example_links %}
|
||||
<h2>API endpoints</h2>
|
||||
<ul class="bullets">
|
||||
{% for database in example_links %}
|
||||
<li>Database: <strong>{{ database.name }}</strong></li>
|
||||
<ul class="bullets">
|
||||
{% for link in database.links %}
|
||||
<li><a href="{{ api_path(link) }}">{{ link.path }}</a> - {{ link.label }} </li>
|
||||
{% endfor %}
|
||||
{% for table in database.tables %}
|
||||
<li><strong>{{ table.name }}</strong>
|
||||
<ul class="bullets">
|
||||
{% for link in table.links %}
|
||||
<li><a href="{{ api_path(link) }}">{{ link.path }}</a> - {{ link.label }} </li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -6,6 +6,7 @@ from datasette.permissions import PERMISSIONS
|
|||
from .base import BaseView
|
||||
import secrets
|
||||
import time
|
||||
import urllib
|
||||
|
||||
|
||||
class JsonDataView(BaseView):
|
||||
|
@ -275,5 +276,115 @@ class ApiExplorerView(BaseView):
|
|||
name = "api_explorer"
|
||||
has_json_alternate = False
|
||||
|
||||
async def example_links(self, request):
|
||||
databases = []
|
||||
for name, db in self.ds.databases.items():
|
||||
if name == "_internal":
|
||||
continue
|
||||
if not db.is_mutable:
|
||||
continue
|
||||
database_visible, _ = await self.ds.check_visibility(
|
||||
request.actor,
|
||||
"view-database",
|
||||
name,
|
||||
)
|
||||
if not database_visible:
|
||||
continue
|
||||
tables = []
|
||||
table_names = await db.table_names()
|
||||
for table in table_names:
|
||||
visible, _ = await self.ds.check_visibility(
|
||||
request.actor,
|
||||
"view-table",
|
||||
(name, table),
|
||||
)
|
||||
if not visible:
|
||||
continue
|
||||
table_links = []
|
||||
table_links.append(
|
||||
{
|
||||
"label": "Get rows for {}".format(table),
|
||||
"method": "GET",
|
||||
"path": self.ds.urls.table(name, table, format="json")
|
||||
+ "?_shape=objects".format(name, table),
|
||||
}
|
||||
)
|
||||
if await self.ds.permission_allowed(
|
||||
request.actor, "insert-row", (name, table)
|
||||
):
|
||||
pks = await db.primary_keys(table)
|
||||
table_links.append(
|
||||
{
|
||||
"path": self.ds.urls.table(name, table) + "/-/insert",
|
||||
"method": "POST",
|
||||
"label": "Insert rows into {}".format(table),
|
||||
"json": {
|
||||
"rows": [
|
||||
{
|
||||
column: None
|
||||
for column in await db.table_columns(table)
|
||||
if column not in pks
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
)
|
||||
if await self.ds.permission_allowed(
|
||||
request.actor, "drop-table", (name, table)
|
||||
):
|
||||
table_links.append(
|
||||
{
|
||||
"path": self.ds.urls.table(name, table) + "/-/drop",
|
||||
"label": "Drop table {}".format(table),
|
||||
"json": {},
|
||||
"method": "POST",
|
||||
}
|
||||
)
|
||||
tables.append({"name": table, "links": table_links})
|
||||
database_links = []
|
||||
if await self.ds.permission_allowed(request.actor, "create-table", name):
|
||||
database_links.append(
|
||||
{
|
||||
"path": self.ds.urls.database(name) + "/-/create",
|
||||
"label": "Create table in {}".format(name),
|
||||
"json": {
|
||||
"table": "new_table",
|
||||
"columns": [
|
||||
{"name": "id", "type": "integer"},
|
||||
{"name": "name", "type": "text"},
|
||||
],
|
||||
"pk": "id",
|
||||
},
|
||||
"method": "POST",
|
||||
}
|
||||
)
|
||||
if database_links or tables:
|
||||
databases.append(
|
||||
{
|
||||
"name": name,
|
||||
"links": database_links,
|
||||
"tables": tables,
|
||||
}
|
||||
)
|
||||
return databases
|
||||
|
||||
async def get(self, request):
|
||||
return await self.render(["api_explorer.html"], request)
|
||||
def api_path(link):
|
||||
return "/-/api#{}".format(
|
||||
urllib.parse.urlencode(
|
||||
{
|
||||
key: json.dumps(value, indent=2) if key == "json" else value
|
||||
for key, value in link.items()
|
||||
if key in ("path", "method", "json")
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
return await self.render(
|
||||
["api_explorer.html"],
|
||||
request,
|
||||
{
|
||||
"example_links": await self.example_links(request),
|
||||
"api_path": api_path,
|
||||
},
|
||||
)
|
||||
|
|
Ładowanie…
Reference in New Issue