Files

135 lines
3.6 KiB
Markdown
Raw Permalink 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.
# Movie Collection API
A simple Movie Collection REST API built with **Node.js + Express**, plus a single-page
frontend that talks to it with `fetch()`.
A **Movie** is one entry in the collection; the collection is `/api/movies`. Movies are
kept in a plain JavaScript array, so **there is no database — records added through the
API disappear when the server restarts.**
## Running
```sh
npm install
npm start # node server.js
```
Open <http://localhost:3000>.
```sh
npm run dev # node --watch server.js
PORT=4000 npm start
```
## Schema
Each movie has four fields:
| Field | Type | Notes |
| --- | --- | --- |
| `id` | integer ≥ 1 | **assigned by the server**, never sent by the client |
| `title` | string, 1–120 chars | required, trimmed |
| `genre` | string, 1–60 chars | required, trimmed |
| `year` | integer, 1888–2100 | required; `"2010"` and `2010` are both accepted |
The three request fields are required. Anything missing or blank comes back as a `400`
with one message per field.
## Endpoints
| Method | Path | Result |
| --- | --- | --- |
| `GET` | `/api/movies` | all movies → `200` |
| `GET` | `/api/movies/:id` | one movie → `200`, or `404` if there is no such id |
| `POST` | `/api/movies` | add a movie → `201` with a `Location` header |
| `GET` | `/` | the frontend |
Errors come back as a message plus the offending fields:
```json
{ "error": "Title is required.", "fields": { "title": "Title is required.", "year": "Year is required." } }
```
## Examples
```sh
curl http://localhost:3000/api/movies
curl http://localhost:3000/api/movies/2
curl -X POST http://localhost:3000/api/movies \
-H 'content-type: application/json' \
-d '{"title":"Inception","genre":"science fiction","year":2010}'
```
`GET /api/movies` → `200`
```json
[
{ "id": 1, "title": "Interstellar", "genre": "Science Fiction", "year": 2014 },
{ "id": 2, "title": "Avengers: Endgame", "genre": "Action", "year": 2019 },
{ "id": 3, "title": "Coco", "genre": "Animation", "year": 2017 }
]
```
`POST /api/movies` → `201` · `Location: /api/movies/4`
```json
{ "id": 4, "title": "Inception", "genre": "science fiction", "year": 2010 }
```
`POST /api/movies` with `{}` → `400`
```json
{
"error": "Title is required.",
"fields": {
"title": "Title is required.",
"genre": "Genre is required.",
"year": "Year is required."
}
}
```
`GET /api/movies/abc` → `400`
```json
{ "error": "ID must be a whole number, like 1." }
```
`GET /api/movies/99` → `404`
```json
{ "error": "No movie with ID 99." }
```
## Frontend
`index.html` is a single file (no build step, no framework) served by the same Express
app. It:
- displays the movie list in a table,
- has a form for adding a movie (title, genre, year),
- uses `fetch()` for every call to the API,
- refreshes the list after a movie is added.
Clicking a row fetches that one movie from `GET /api/movies/:id` and shows it in a detail
panel, so all three endpoints are exercised from the UI.
## Files
```
server.js Express app: schemas, in-memory store, routes, error handling
index.html the frontend (styles + fetch logic, no dependencies)
package.json express + zod
```
## Project structure notes
- **Storage** is `const movies = []` in `server.js`, with a `nextId` counter for the
auto-assigned `id`. It is seeded with three movies on startup.
- **Validation** uses [zod](https://zod.dev). One schema per shape (`movieDraftSchema`
for the request body, `movieSchema` for what is stored and returned), and a small
helper turns a failure into the `{ error, fields }` response the frontend renders next
to each input.
- `node_modules/` is git-ignored.