68 lines
3.2 KiB
Markdown
68 lines
3.2 KiB
Markdown
# Gotchas
|
|
|
|
> What trips up API clients: session-only routes, error texts, rate limits and draft visibility.
|
|
|
|
## Session-only routes
|
|
|
|
An API key cannot call these routes. They answer `403` with a plain-text body and no JSON:
|
|
|
|
```
|
|
HTTP/1.1 403 Forbidden
|
|
|
|
This action needs a real session.
|
|
```
|
|
|
|
- `/v1/api-key/*`, `/v1/system/*`, `POST /v1/auth/verify`, `DELETE /v1/auth/register`.
|
|
- Every activity route under `/v1/activity`.
|
|
- Writes on sites (`POST`, `PATCH`, `DELETE` under `/v1/site`, so a key cannot create a site) and on authors (`POST`, `PATCH`, `DELETE` under `/v1/author`).
|
|
- `PATCH /v1/settings`.
|
|
|
|
Variant routes under `/v1/media/{id}/variants` answer `401` to a key instead. The sign-in routes (login, logout, register, password reset) ignore a key and give no `403`.
|
|
|
|
When a task needs one of these routes, stop and tell the user to do it in the app. Do not try to log in with a password.
|
|
|
|
## Error texts are plain text
|
|
|
|
Errors are not JSON. The body is one sentence; branch on the status code, and show the sentence to the user.
|
|
|
|
| Status | Typical text |
|
|
| --- | --- |
|
|
| `400` | `The request cannot be processed due to a mismatch in the format of the body.` |
|
|
| `401` | `You must be logged in to access this resource.` |
|
|
| `403` | `This action needs a real session.`, `Only the owner can do this.`, `Only owners and admins can do this.`, `You must verify your account to access this resource.` |
|
|
| `404` | `Article not found`, `Image not found` |
|
|
| `429` | `Too many requests. Please try again later.` |
|
|
|
|
An invalid, unknown, expired or revoked key answers `401`, even on public routes. It is never treated as anonymous.
|
|
|
|
## Rate limit: 429
|
|
|
|
Each key may make 120 requests per minute. The `429` response carries a `Retry-After` header holding the seconds to wait:
|
|
|
|
```
|
|
HTTP/1.1 429 Too Many Requests
|
|
Retry-After: 46
|
|
|
|
Too many requests. Please try again later.
|
|
```
|
|
|
|
Sleep for `Retry-After` seconds, then retry once. Do not retry in a tight loop. Prefer one list call with `size=100` over many single reads.
|
|
|
|
## Draft versus online
|
|
|
|
- Anonymous callers and unverified users only see online articles. A draft answers `404` with `Article not found`, the same as an id that does not exist.
|
|
- A verified session or a key sees drafts as well. In lists, `counts.draft` is `0` for anonymous callers and `status=draft` answers an empty page.
|
|
- `POST /v1/article/` always creates a draft. Publishing is a separate call, `PATCH /v1/article/{id}/publish`.
|
|
- Sitemaps list online articles only.
|
|
|
|
## Writes
|
|
|
|
- A title cannot be changed after creation. Create a new article instead.
|
|
- `PATCH /v1/article/{id}` accepts `body`, `site_id`, `author_ids` and the SEO fields only. `{}` and `null` values answer `400`, except `cover_image_id` and `social_image_id`, where `null` removes the image.
|
|
- Request bodies are HTML even though responses default to markdown. Send `<p>` and `<h2>`, not markdown syntax, or it is stored literally.
|
|
- Ids in paths are unsigned integers. Anything else answers `400`.
|
|
|
|
## Permissions follow the key's creator
|
|
|
|
A key acts as the user who made it. A key made by a user who is neither owner nor admin cannot do what only owners and admins can, and it answers `403 Only owners and admins can do this.` Check `GET /v1/auth/me` to read the role of the key.
|