wiki: add Routes Reference page

2026-05-29 02:13:18 +00:00
parent 6843825bdd
commit 95c0695ed5

69
Routes-Reference.md Normal file

@@ -0,0 +1,69 @@
# Routes Reference
`service.router()` registers exactly these routes:
| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/inbox` | Shared inbox — HTTP sig verification + dispatch, 1 MB limit |
| `POST` | `/users/{id}/inbox` | Per-user inbox — same |
| `GET` | `/users/{id}/outbox` | Cursor-based `OrderedCollection` |
| `GET` | `/users/{id}/featured` | Pinned posts `OrderedCollection` |
| `GET` | `/.well-known/webfinger` | JRD with `aliases` field |
| `GET` | `/.well-known/nodeinfo` | Redirect to `/nodeinfo/2.0` |
| `GET` | `/nodeinfo/2.0` | NodeInfo 2.0 document |
---
## Routes NOT registered
`GET /users/{id}`, `GET /users/{id}/followers`, and `GET /users/{id}/following` are **not** registered by `service.router()`.
These paths must serve both AP JSON (for federation) and your UI JSON (for your frontend) based on the `Accept` header. k-ap can't do the UI half, so your application owns the route and calls k-ap's helper methods for the AP half.
---
## Content negotiation pattern
```rust
use axum::{extract::{Path, State}, http::HeaderMap, response::IntoResponse, Json};
async fn actor_handler(
Path(username): Path<String>,
headers: HeaderMap,
State(state): State<AppState>,
) -> impl IntoResponse {
let user = state.db.find_user_by_username(&username).await?;
if wants_ap_json(&headers) {
// actor_json takes a UUID as a string
let json = state.service.actor_json(&user.id.to_string()).await?;
return (
[(axum::http::header::CONTENT_TYPE, "application/activity+json")],
json,
).into_response();
}
// Return your UI JSON or HTML
Json(MyUserResponse::from(user)).into_response()
}
fn wants_ap_json(headers: &HeaderMap) -> bool {
headers
.get("accept")
.and_then(|v| v.to_str().ok())
.map(|v| v.contains("application/activity+json") || v.contains("application/ld+json"))
.unwrap_or(false)
}
```
The same pattern for followers and following. `page` is `Option<u32>` — pass `None` for the collection root, `Some(n)` for a page:
```rust
// In your followers handler:
let json = state.service.followers_collection_json(user.id, page).await?;
// In your following handler:
let json = state.service.following_collection_json(user.id, page).await?;
```
Both return JSON strings with the correct `@context` and `OrderedCollection` structure.