Skip to content

Commit b80b66d

Browse files
committed
Add docs about JSON API
1 parent c7ab0fb commit b80b66d

File tree

2 files changed

+135
-10
lines changed

2 files changed

+135
-10
lines changed

README.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,122 @@
33
Yet Another inDEX page.
44

55
Designed to work with other servers like nginx -- yadex does not serve files, instead it only generates index pages for directories.
6+
7+
## Endpoints
8+
9+
### Template-rendered index page
10+
11+
Enabled with `template_index` config option in `[service]` (default: true). You need to set `index_file` in `[template]` config section (relative to config dir).
12+
13+
Template example: [etc/index.html](etc/index.html)
14+
15+
### JSON API
16+
17+
Enabled with `json_api` config option in `[service]` (default: false). The path is `/api/files`, and shall be called with a POST request with a JSON body:
18+
19+
```json
20+
{
21+
"path": "/path/to/directory"
22+
}
23+
```
24+
25+
Example response (note: entries are not sorted):
26+
27+
```json
28+
{
29+
"entries": [
30+
{
31+
"name": "hooks",
32+
"is_dir": true,
33+
"size": 556,
34+
"href": "/.git/hooks/",
35+
"datetime": 1762543427
36+
},
37+
{
38+
"name": "info",
39+
"is_dir": true,
40+
"size": 14,
41+
"href": "/.git/info/",
42+
"datetime": 1762543427
43+
},
44+
{
45+
"name": "description",
46+
"is_dir": false,
47+
"size": 73,
48+
"href": "/.git/description",
49+
"datetime": 1762543427
50+
},
51+
{
52+
"name": "objects",
53+
"is_dir": true,
54+
"size": 408,
55+
"href": "/.git/objects/",
56+
"datetime": 1762890787
57+
},
58+
{
59+
"name": "refs",
60+
"is_dir": true,
61+
"size": 32,
62+
"href": "/.git/refs/",
63+
"datetime": 1762543429
64+
},
65+
{
66+
"name": "packed-refs",
67+
"is_dir": false,
68+
"size": 216,
69+
"href": "/.git/packed-refs",
70+
"datetime": 1762543429
71+
},
72+
{
73+
"name": "logs",
74+
"is_dir": true,
75+
"size": 16,
76+
"href": "/.git/logs/",
77+
"datetime": 1762543429
78+
},
79+
{
80+
"name": "HEAD",
81+
"is_dir": false,
82+
"size": 21,
83+
"href": "/.git/HEAD",
84+
"datetime": 1762543429
85+
},
86+
{
87+
"name": "COMMIT_EDITMSG",
88+
"is_dir": false,
89+
"size": 40,
90+
"href": "/.git/COMMIT_EDITMSG",
91+
"datetime": 1762890785
92+
},
93+
{
94+
"name": "FETCH_HEAD",
95+
"is_dir": false,
96+
"size": 82,
97+
"href": "/.git/FETCH_HEAD",
98+
"datetime": 1762890787
99+
},
100+
{
101+
"name": "config",
102+
"is_dir": false,
103+
"size": 284,
104+
"href": "/.git/config",
105+
"datetime": 1762546352
106+
},
107+
{
108+
"name": "index",
109+
"is_dir": false,
110+
"size": 1635,
111+
"href": "/.git/index",
112+
"datetime": 1762890785
113+
},
114+
{
115+
"name": "ORIG_HEAD",
116+
"is_dir": false,
117+
"size": 41,
118+
"href": "/.git/ORIG_HEAD",
119+
"datetime": 1762890787
120+
}
121+
],
122+
"maybe_truncated": false
123+
}
124+
```

src/server.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use axum::{
1111
extract::{Json, State},
1212
http::Uri,
1313
response::{Html, IntoResponse, Redirect, Response},
14-
routing::get,
14+
routing::{get, post},
1515
};
1616
use chrono::{TimeZone, Utc};
1717
use futures_util::StreamExt as SExt;
@@ -114,7 +114,7 @@ impl App {
114114
router = router.fallback(get(directory_listing));
115115
}
116116
if config.json_api {
117-
router = router.route("/api/files", get(api_directory_listing));
117+
router = router.route("/api/files", post(api_directory_listing));
118118
}
119119
let router = router.with_state(AppState {
120120
limit: if config.limit == 0 {
@@ -202,7 +202,11 @@ fn remove_first_component<P: AsRef<Path>>(path: P) -> PathBuf {
202202
}
203203
}
204204

205-
async fn get_entries(path: &Path, limit: usize) -> Result<Vec<DirEntryInfo>, YadexError> {
205+
async fn get_entries(
206+
path: &Path,
207+
limit: usize,
208+
sort: bool,
209+
) -> Result<Vec<DirEntryInfo>, YadexError> {
206210
let mut entries = ReadDirStream::new(tokio::fs::read_dir(path).await.context(NotFoundSnafu)?)
207211
.take(limit)
208212
.filter_map(async |entry| match direntry_info(entry).await {
@@ -228,11 +232,13 @@ async fn get_entries(path: &Path, limit: usize) -> Result<Vec<DirEntryInfo>, Yad
228232
})
229233
.collect::<Vec<_>>()
230234
.await;
231-
entries.sort_by(|a, b| match (a.is_dir, b.is_dir) {
232-
(true, false) => std::cmp::Ordering::Less,
233-
(false, true) => std::cmp::Ordering::Greater,
234-
_ => a.name.to_lowercase().cmp(&b.name.to_lowercase()),
235-
});
235+
if sort {
236+
entries.sort_by(|a, b| match (a.is_dir, b.is_dir) {
237+
(true, false) => std::cmp::Ordering::Less,
238+
(false, true) => std::cmp::Ordering::Greater,
239+
_ => a.name.to_lowercase().cmp(&b.name.to_lowercase()),
240+
});
241+
}
236242
Ok(entries)
237243
}
238244

@@ -260,7 +266,7 @@ pub async fn api_directory_listing(
260266
let path = path.as_path();
261267
tracing::debug!("API listing directory: {:?}", path);
262268

263-
let entries = get_entries(path, state.limit).await?;
269+
let entries = get_entries(path, state.limit, false).await?;
264270
let maybe_truncated = entries.len() == state.limit;
265271
let output = APIOutput {
266272
entries,
@@ -291,7 +297,7 @@ pub async fn directory_listing(
291297
let path = path.as_path();
292298
tracing::debug!("listing directory: {:?}", path);
293299

294-
let entries = get_entries(path, state.limit).await?;
300+
let entries = get_entries(path, state.limit, true).await?;
295301
let html = state
296302
.template
297303
.render(

0 commit comments

Comments
 (0)