|
| 1 | +Endpoint for Efficiently Querying an Asset or Folder at a Given Path |
| 2 | +==================================================================== |
| 3 | + |
| 4 | +[`dandidav`](https://github.com/dandi/dandidav), the WebDAV interface to the |
| 5 | +DANDI Archive, fetches all of its information about the Archive via the Archive |
| 6 | +REST API; unfortunately, the API's support for getting all of the necessary |
| 7 | +information about assets & folders at a given path is incredibly suboptimal, |
| 8 | +resulting in multiple API requests per WebDAV request, including making a |
| 9 | +separate request for each & every asset immediately within a folder. |
| 10 | + |
| 11 | +This design doc therefore proposes the addition of a new endpoint to the |
| 12 | +Archive API that can be used to answer all of the following questions in a |
| 13 | +single (possibly paginated) request: |
| 14 | + |
| 15 | +- Is the resource at a given path an asset, a folder, or nonexistent? |
| 16 | + |
| 17 | +- If the resource is an asset, what are its properties and, optionally, |
| 18 | + its metadata? |
| 19 | + |
| 20 | +- Optionally, if the resource is a folder, what are all of its children — both |
| 21 | + assets and subfolders — and, for child assets, what are their properties and |
| 22 | + metadata? |
| 23 | + |
| 24 | +Requests |
| 25 | +-------- |
| 26 | + |
| 27 | +A `GET` endpoint shall be added at |
| 28 | +`/dandisets/{dandiset_id}/versions/{version_id}/assets/atpath/`. The endpoint |
| 29 | +shall take the following query parameters: |
| 30 | + |
| 31 | +- `path` — A normalized forward-slash-separated relative path, identifying the |
| 32 | + asset or folder to return information on. |
| 33 | + |
| 34 | + - If this parameter is absent or empty, the request is for the root |
| 35 | + directory of the Dandiset version's file hierarchy. |
| 36 | + |
| 37 | + - If the path is present but no resource exists at the given path, a 404 |
| 38 | + response is returned. |
| 39 | + |
| 40 | + - For the purposes of this endpoint, empty folders do not exist. |
| 41 | + |
| 42 | + - If the path ends in a forward slash and no folder exists at the given |
| 43 | + path, a 404 is returned, even if an asset exists at the path with the |
| 44 | + trailing slash removed. |
| 45 | + |
| 46 | +- `metadata` — Whether to include asset metadata in the response; possible |
| 47 | + values are `false` (the default), indicating that metadata should not be |
| 48 | + included, and `true`, indicating that metadata should be included. |
| 49 | + |
| 50 | + - Values that cannot be parsed to `true` or `false` using Django's |
| 51 | + `BooleanField` result in a 400 response. |
| 52 | + |
| 53 | +- `children` — Whether to include children of `path` in the response; possible |
| 54 | + values are `false` (the default), indicating that children should not be |
| 55 | + included, and `true`, indicating that children should be included. |
| 56 | + |
| 57 | + - This parameter has no effect when the resource at `path` is an asset |
| 58 | + rather than a folder. |
| 59 | + |
| 60 | + - Values that cannot be parsed to `true` or `false` using Django's |
| 61 | + `BooleanField` result in a 400 response. |
| 62 | + |
| 63 | +- `page` and `page_size` — Pagination parameters |
| 64 | + |
| 65 | +Responses |
| 66 | +--------- |
| 67 | + |
| 68 | +All successful responses from this endpoint shall be structured as a paginated |
| 69 | +list, using the same pagination schema as is already used for other endpoints. |
| 70 | + |
| 71 | +- When `path` points to an asset, the list shall contain a single item: a JSON |
| 72 | + object containing the following fields: |
| 73 | + |
| 74 | + - `"type"` — Always has a value of `"asset"` |
| 75 | + |
| 76 | + - `"resource"` — A sub-object containing the properties of the asset at |
| 77 | + `path` (i.e., `asset_id`, `blob`, `zarr`, `path`, `size`, `created`, and |
| 78 | + `modified`). If `metadata=1` was supplied in the request, this |
| 79 | + sub-object shall also contain a `"metadata"` field containing the asset's |
| 80 | + metadata. |
| 81 | + |
| 82 | +- When `path` points to a non-root folder, the first element of the list shall |
| 83 | + be a JSON object containing the following fields: |
| 84 | + |
| 85 | + - `"type"` — Always has a value of `"folder"` |
| 86 | + |
| 87 | + - `"resource"` — A sub-object containing the following fields: |
| 88 | + |
| 89 | + - `"path"` — the path of the folder, without a trailing slash |
| 90 | + |
| 91 | + - `"total_assets"` — an integer giving the total number of assets in |
| 92 | + this folder and all of its descendants |
| 93 | + |
| 94 | + - `"total_size"` — an integer giving the total size in bytes of all |
| 95 | + assets in this folder and all of its descendants |
| 96 | + |
| 97 | + If the `children` parameter was not set to `true` in the request, this is the |
| 98 | + only element of the list. Otherwise, the rest of the list consists of JSON |
| 99 | + objects for the assets and subfolders immediately within the folder, ordered |
| 100 | + by their paths (without trailing slashes) and sorted in UTF-8 byte-wise |
| 101 | + order. |
| 102 | + |
| 103 | + - Each asset is represented by an object with the same schema as described |
| 104 | + above for when `path` points to an asset, including `"metadata"` being |
| 105 | + present when `metadata=1` was supplied in the request. |
| 106 | + |
| 107 | + - Each subfolder is represented by an object with the same schema as |
| 108 | + described above for the folder at `path`. |
| 109 | + |
| 110 | +- When `path` is empty or absent, the list shall be the same as for a folder |
| 111 | + located at the root of the file hierarchy, except that there shall be no |
| 112 | + initial element describing the resource at `path`. (Hence, if `children` is |
| 113 | + not `true`, the list shall be empty.) |
| 114 | + |
| 115 | +Example |
| 116 | +------- |
| 117 | + |
| 118 | +A request for |
| 119 | +`/dandisets/000029/versions/0.231017.2004/assets/atpath/?metadata=true&children=true` |
| 120 | +would have a response of: |
| 121 | + |
| 122 | +```json |
| 123 | +{ |
| 124 | + "count": 9, |
| 125 | + "next": null, |
| 126 | + "previous": null, |
| 127 | + "results": [ |
| 128 | + { |
| 129 | + "type": "asset", |
| 130 | + "resource": { |
| 131 | + "asset_id": "1ab0d4ff-1231-48c9-a8a3-8145552830a4", |
| 132 | + "blob": "2fd7464f-5459-4c96-a938-27cf13f4d330", |
| 133 | + "zarr": null, |
| 134 | + "path": "bar-renamed-3334", |
| 135 | + "size": 4, |
| 136 | + "created": "2023-09-27T17:08:32.039960Z", |
| 137 | + "modified": "2023-10-17T19:55:40.394757Z", |
| 138 | + "metadata": "--- SNIPPED FOR BREVITY ---" |
| 139 | + } |
| 140 | + }, |
| 141 | + { |
| 142 | + "type": "asset", |
| 143 | + "resource": { |
| 144 | + "asset_id": "ad49cd65-184a-4dad-8dde-523e7aaab56c", |
| 145 | + "blob": "56f5b879-e5fa-476c-9893-dab482f66b3d", |
| 146 | + "zarr": null, |
| 147 | + "path": "baz", |
| 148 | + "size": 4, |
| 149 | + "created": "2023-03-16T15:50:06.908811Z", |
| 150 | + "modified": "2023-03-17T15:41:18.403892Z", |
| 151 | + "metadata": "--- SNIPPED FOR BREVITY ---" |
| 152 | + } |
| 153 | + }, |
| 154 | + { |
| 155 | + "type": "folder", |
| 156 | + "resource": { |
| 157 | + "path": "sub-anm369962", |
| 158 | + "total_assets": 1, |
| 159 | + "total_size": 6644036 |
| 160 | + } |
| 161 | + }, |
| 162 | + { |
| 163 | + "type": "folder", |
| 164 | + "resource": { |
| 165 | + "path": "sub-anm369963", |
| 166 | + "total_assets": 1, |
| 167 | + "total_size": 6393196 |
| 168 | + } |
| 169 | + }, |
| 170 | + { |
| 171 | + "type": "folder", |
| 172 | + "resource": { |
| 173 | + "path": "sub-anm369964", |
| 174 | + "total_assets": 1, |
| 175 | + "total_size": 7660100 |
| 176 | + } |
| 177 | + }, |
| 178 | + { |
| 179 | + "type": "folder", |
| 180 | + "resource": { |
| 181 | + "path": "sub-monk-g", |
| 182 | + "total_assets": 1, |
| 183 | + "total_size": 18295752 |
| 184 | + } |
| 185 | + }, |
| 186 | + { |
| 187 | + "type": "folder", |
| 188 | + "resource": { |
| 189 | + "path": "sub-RAT123", |
| 190 | + "total_assets": 1, |
| 191 | + "total_size": 18792 |
| 192 | + } |
| 193 | + }, |
| 194 | + { |
| 195 | + "type": "asset", |
| 196 | + "resource": { |
| 197 | + "asset_id": "c7913fad-ccc6-467f-a4b6-a9b62af6d98f", |
| 198 | + "blob": "0317cf5a-4047-4e19-aae1-4f7b7434d2d7", |
| 199 | + "zarr": null, |
| 200 | + "path": "test1234", |
| 201 | + "size": 9, |
| 202 | + "created": "2023-03-16T15:50:06.762183Z", |
| 203 | + "modified": "2023-03-17T15:41:18.369626Z", |
| 204 | + "metadata": "--- SNIPPED FOR BREVITY ---" |
| 205 | + } |
| 206 | + }, |
| 207 | + { |
| 208 | + "type": "asset", |
| 209 | + "resource": { |
| 210 | + "asset_id": "bb612483-0a97-4309-9763-7fb518265c70", |
| 211 | + "blob": "0317cf5a-4047-4e19-aae1-4f7b7434d2d7", |
| 212 | + "zarr": null, |
| 213 | + "path": "test12345", |
| 214 | + "size": 9, |
| 215 | + "created": "2023-03-16T15:50:07.184996Z", |
| 216 | + "modified": "2023-03-17T15:41:18.378517Z", |
| 217 | + "metadata": "--- SNIPPED FOR BREVITY ---" |
| 218 | + } |
| 219 | + } |
| 220 | + ] |
| 221 | +} |
| 222 | +``` |
0 commit comments