Files
bookhoard/docs/developer/api/media-items/upsert_media_review.md
T
John O'Keefe ed0ce5d077 docs(media-items): Work Order 3 batch 3a — reader-adjacent CRUD (11 endpoints)
New frontmatter'd docs with real shapes (sqlc models pinned directly):
- bookmarks: get/create/update/delete (sync-aware rows: dedup_key,
  last_modified_*, tombstones; delete is 204)
- review: upsert (empty string DELETES the review) / get (200 with
  {review:null} when absent) / delete
- get single note + highlight (full sqlc row shapes)
- annotation history: restore (POST, kind via query or body) and purge
  (DELETE, kind via required query; permanent)

Gate hardening forced by this batch:
- required-field walk now guards non-struct Request types (RawMessage pins)
- update_media_bookmark needed a full example block (no cross-reference
  shortcuts — the gate checks every doc standalone)
2026-10-24 15:03:36 -04:00

44 lines
1.1 KiB
Markdown

---
method: POST
path: /api/media-items/:id/review
auth: jwt
area: media-items
---
<!-- source: internal/handlers/media.go:1072 MediaHandler.UpsertMediaReview -->
# Upsert Media Review
Sets (or updates) the user's personal review for a media item. **An empty /
whitespace review deletes the stored review instead** and returns
`{"review": null}`.
`PUT /api/media-items/:id/review` is the same handler and behaves identically.
## Example request
```json example-request
{
"review": "A slow start, but the second act earns it."
}
```
## Example response
```json example-response
{
"id": "220e8400-e29b-41d4-a716-446655440000",
"media_item_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "92413c3a-e1b8-4fff-b3f9-95c74478d19a",
"review": "A slow start, but the second act earns it.",
"created_at": "2026-10-24T13:57:01Z",
"updated_at": "2026-10-24T13:57:01Z"
}
```
## Errors
| Status | Body | When |
| ------ | ---- | ---- |
| 400 | `{"error": "invalid request"}` / `{"error": "invalid media item id"}` | malformed |
| 500 | `{"error": "..."}` | unexpected server error |