Homepage JSON returns databases as a list

/.json previously returned databases as an object keyed by database
name, unlike /-/databases.json and every other collection in the API.
It now returns a list of database objects. The HTML template already
consumed the list. This endpoint remains undocumented.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
This commit is contained in:
Claude 2026-07-04 16:45:19 +00:00
commit 5cb2bc6909
No known key found for this signature in database
4 changed files with 17 additions and 13 deletions

View file

@ -152,7 +152,7 @@ class IndexView(BaseView):
json.dumps(
{
"ok": True,
"databases": {db["name"]: db for db in databases},
"databases": databases,
"metadata": await self.ds.get_instance_metadata(),
},
cls=CustomJSONEncoder,

View file

@ -201,8 +201,8 @@ Routes: `/(\.(?P<format>jsono?))?$` and `/-/(\.(?P<format>jsono?))?$`
- **Parameters:** `_sort=relationships` sorts each database's truncated table
list by foreign-key relationship count.
- **JSON response** (index.py:147-161) — includes `ok: true` plus:
- `databases` — an **object keyed by database name** (not a list). Each
value: `name`, `hash` (or null), `color`, `path`,
- `databases` — a **list** of database objects (undocumented API, subject
to change). Each item: `name`, `hash` (or null), `color`, `path`,
`tables_and_views_truncated` (up to 5 items: `name`, `columns`,
`primary_keys`, `count` (int or null), `hidden`, `fts_table`,
`num_relationships_for_sorting`, `private`; view items are just

View file

@ -156,10 +156,12 @@ Endpoints disagree about the success envelope:
### 2a. Collection representations disagree (P2)
- Homepage `/.json` returns `databases` as an **object keyed by name**
- ~~Homepage `/.json` returns `databases` as an **object keyed by name**
(index.py:147-161); `/-/databases.json` returns an **array**; the database
page returns `tables` as an array. Choose arrays-of-objects everywhere
(objects-keyed-by-name break when names need ordering or pagination).
(objects-keyed-by-name break when names need ordering or pagination).~~
**Done** — the homepage returns a list, matching `/-/databases.json`.
The homepage JSON remains deliberately undocumented.
- ~~Insert/upsert with `return: true` respond with `rows` (plural, list); row
update with `return: true` responds with `row` (singular, object)
(views/row.py:837-844). Pick one (`rows` everywhere, even for one row,

View file

@ -26,8 +26,9 @@ async def test_homepage(ds_client):
"title",
]
databases = data.get("databases")
assert databases.keys() == {"fixtures": 0}.keys()
d = databases["fixtures"]
assert isinstance(databases, list)
assert [d["name"] for d in databases] == ["fixtures"]
d = databases[0]
assert d["name"] == "fixtures"
assert isinstance(d["tables_count"], int)
assert isinstance(len(d["tables_and_views_truncated"]), int)
@ -43,7 +44,7 @@ async def test_homepage_sort_by_relationships(ds_client):
assert response.status_code == 200
tables = [
t["name"]
for t in response.json()["databases"]["fixtures"]["tables_and_views_truncated"]
for t in response.json()["databases"][0]["tables_and_views_truncated"]
]
assert tables == [
"simple_primary_key",
@ -251,8 +252,8 @@ def test_no_files_uses_memory_database(app_client_no_files):
assert response.status == 200
assert {
"ok": True,
"databases": {
"_memory": {
"databases": [
{
"name": "_memory",
"hash": None,
"color": "a6c7b9",
@ -267,7 +268,7 @@ def test_no_files_uses_memory_database(app_client_no_files):
"views_count": 0,
"private": False,
},
},
],
"metadata": {},
} == response.json
# Try that SQL query
@ -852,8 +853,9 @@ async def test_tilde_encoded_database_names(db_name):
ds = Datasette()
ds.add_memory_database(db_name)
response = await ds.client.get("/.json")
assert db_name in response.json()["databases"].keys()
path = response.json()["databases"][db_name]["path"]
databases_by_name = {d["name"]: d for d in response.json()["databases"]}
assert db_name in databases_by_name
path = databases_by_name[db_name]["path"]
# And the JSON for that database
response2 = await ds.client.get(path + ".json")
assert response2.status_code == 200