Files
Art-gallery/Documentation/API.md
T
Danila KhodjaefandCursor 08f99d7a29 Redesign 3D gallery as single hall per artist with exit navigation.
Restore React client source, add hall-to-hall navigation via painting influences grouped by movement, and update documentation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-19 10:10:13 +03:00

190 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Art Gallery — REST API
Base URL in development:
- **Direct:** `http://localhost:3001`
- **Via Vite proxy:** `http://localhost:5173` (same paths)
All JSON responses use `Content-Type: application/json`. Errors return `{ "error": "message" }` with an appropriate HTTP status.
Static images are served at `/images/<relative-path>` from `IMAGE_DIR`.
---
## `GET /api/bounds`
Returns the overall timeline year range used to initialise the zoomable timeline.
**Response**
```json
{
"min_year": -800,
"max_year": 2100
}
```
`min_year` is the earliest art movement start; `max_year` is the latest of era ends, movement ends, and artist death years.
---
## `GET /api/timeline`
Historical eras and art movements overlapping a year window.
**Query**
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `start` | int | -3000 | Window start year |
| `end` | int | 2100 | Window end year |
**Response**
```json
{
"eras": [ { "id": 1, "name": "Renaissance", "start_year": 1300, "end_year": 1600, "start_definite": false, "end_definite": false, "description": "...", "sort_order": 3 } ],
"movements": [ { "id": 5, "name": "Impressionism", "start_year": 1860, "end_year": 1890, "era_id": 6, "era_name": "Modern", "color": "#87CEEB", ... } ]
}
```
Movements are filtered to those with at least one artist active in the requested range.
---
## `GET /api/artists`
Artists for timeline portraits and movement bands.
**Query**
| Param | Type | Description |
|-------|------|-------------|
| `start` | int | Only artists alive after this year |
| `end` | int | Only artists born before this year |
| `movement_id` | int | Filter by movement |
**Response** — array of artist objects with joined `movement_name` and `movement_color`.
---
## `GET /api/movements/:id/artists`
Artists belonging to a single movement.
**Response** — array of `{ id, name, birth_year, death_year, portrait_path, bio_short }`.
---
## `GET /api/artists/:id`
Full artist profile for the bio page and 3D gallery entry.
**Response**
```json
{
"artist": { "id": 1, "name": "...", "movement_name": "...", "bio_full": "...", ... },
"periods": [ { "id": 1, "name": "Milan Period", "start_year": 1482, "end_year": 1499, ... } ],
"paintings": [ { "id": 10, "title": "...", "year": 1498, "image_path": "...", "thumbnail_path": "...", ... } ]
}
```
---
## `GET /api/artists/:id/navigation`
Related artists for hall-to-hall navigation at the exit doorway. Derived from `painting_influences`:
- **Predecessors** — artists whose works influenced this artists paintings.
- **Successors** — artists whose works were influenced by this artists paintings.
Both lists are grouped by art movement and exclude the current artist.
**Response**
```json
{
"predecessors": [
{
"movement_id": 4,
"movement_name": "Early Renaissance",
"movement_color": "#B8860B",
"artists": [
{
"id": 12,
"name": "Domenico Ghirlandaio",
"birth_year": 1448,
"death_year": 1494,
"portrait_path": "portraits/Domenico_Ghirlandaio.jpg"
}
]
}
],
"successors": []
}
```
---
## `POST /api/artists/:id/preload-images`
Fast local scan: links paintings to files already on disk. Does **not** download from the internet (safe to call before opening the 3D gallery).
**Response**
```json
{ "fetched": 12, "total": 15 }
```
`fetched` counts paintings with a resolvable local image after the scan.
---
## `GET /api/paintings/:id`
Painting detail with influence graph neighbours.
**Response**
```json
{
"painting": { "id": 10, "title": "...", "artist_name": "...", "image_path": "...", ... },
"influencedBy": [ { "id": 3, "title": "...", "artist_name": "...", "notes": "...", "aspects": "...", "quote": "...", "source_author": "...", ... } ],
"influenced": [ { "id": 20, "title": "...", ... } ]
}
```
---
## `GET /api/paintings/:id/image`
Serves a painting image file. Resolves and caches from external sources only when no local file exists.
**Query**
| Param | Values | Default |
|-------|--------|---------|
| `size` | `thumb`, `full` | `thumb` |
Returns the image bytes with `Cache-Control: public, max-age=86400`, or `404` if unavailable.
---
## Frontend helpers
The React client wraps these endpoints in `client/src/api/client.ts`:
| Function | Maps to |
|----------|---------|
| `api.getBounds()` | `GET /api/bounds` |
| `api.getTimeline(start, end)` | `GET /api/timeline` |
| `api.getArtists(...)` | `GET /api/artists` |
| `api.getArtist(id)` | `GET /api/artists/:id` |
| `api.getArtistNavigation(id)` | `GET /api/artists/:id/navigation` |
| `api.getPainting(id)` | `GET /api/paintings/:id` |
| `preloadArtistImages(id)` | `POST /api/artists/:id/preload-images` |
| `imageUrl(path)` | `/images/<path>` or placeholder |
| `galleryImageUrl(painting)` | Local thumb/full only (3D) |
| `paintingImageUrl(painting)` | Local file or on-demand API |