# Lektion 13 — Express og routes

Christian Budtz — [chbu@dtu.dk](mailto:chbu@dtu.dk)

---

## Program i dag

- Opsamling: framework, route, `my-app`
- Quiz: forberedelsen
- Gennemgang: npm og omskriv `server.js`
- Øvelse 1: Fra `http.createServer` til Express
- Gennemgang: én patient via `:cpr`
- Quiz: routes, `:cpr` og 404
- Øvelse 2: Én patient via `:cpr`
- Gennemgang: `.http`-fil og `POST`
- Quiz: body og status
- Øvelse 3: `POST` fra `api.http`
- Øvelse 4: Tabellen mod jeres server

Pauser lægges ind undervejs.

---

## Læringsmål i dag

Efter lektionen skal du kunne:

- forklare at en route er metode, sti og handler — samme routing som L11-`if`'et
- installere Express med npm og køre `server.js` med samme CORS som før
- svare `GET /api/patients` og `GET /api/patients/:cpr`, og 404 når stien eller CPR'en ikke findes
- tilføje `POST /api/patients` med `express.json()` og passende statuskoder
- teste API'et fra en `.http`-fil i VS Code og se nye patienter i tabellen efter genhentning
- sige, at listen stadig bor i processen — PostgreSQL er lektion 15

---

# Opsamling — forberedelsen

---

## Node venter stadig

`http.createServer` og Express starter begge en proces, der lytter. Uden
`listen` sker der ingenting. Port 3000 er den samme adresse, I brugte i
lektion 11.

Forskellen er, hvordan I vælger handler. I L11 skrev I det selv:

```js
if (req.method === "GET" && req.url === "/api/patients") {
  // ...
}
```

---

## Express skriver routing som routes

En route er metode, sti og funktion. `app.get("/api/patients", …)` er det
`if`, der tjekker `GET` og stien. `app.post(…)` er det samme for `POST`.

Express ligger oven på Node. Den kalder stadig jeres handler, når et request
kommer ind. Frameworket organiserer routingen — det erstatter ikke HTTP.

```mermaid
flowchart LR
  Request["Request: metode + sti"] --> Express
  Express --> Route["Matchende route"]
  Route --> Handler["Handler-funktion"]
  Handler --> Response["Response"]
```

---

## Svar: `send` og `json`

`res.send("Hello World!")` sender tekst. `res.json(patients)` sender JSON
og sætter passende `Content-Type`. Det er det, jeres L11-server gjorde med
`JSON.stringify` og headeren `application/json`.

`res.status(404)` sættes før svaret sendes. I L11 skrev I
`writeHead(404)`. Samme idé.

---

## `my-app` og projektet

I forberedelsen kørte I `index.js` i en mappe for sig. Adresserne
`/` og `/api/patients` viste, at to routes kan leve i samme proces.

I timen åbner vi **gruppens** `server.js` igen. Listen og tabellen er
jeres. Express kommer ind i den fil — ikke i en ny demo-mappe.

---

## Hvad vi ikke tager i dag

Static files — at Express udleverer HTML fra en mappe — hører til
[deploy-vejledningen](../lektion17/deploy.md), når siden og API'et får samme
adresse.

---

# Quiz — forberedelsen

---

## Quiz!

Gå til [/quiz](/quiz) og indtast koden fra tavlen.

**Lektion 13: forberedelse** — Express, route, `send` og `json`.

---

# Gennemgang — Express i `server.js`

---

## npm og afhængighed

Express er et npm-modul. I projektmappen:

```bash
npm init -y
npm install express
```

`package.json` og `node_modules/` hører til projektet. Commit
`package.json` og `package-lock.json`. Commit ikke `node_modules/` — skriv
`node_modules/` i en `.gitignore` i projektmappen.

Start serveren med `node server.js` — samme kommando som før.

---

## Skelet

```js
const express = require("express");

const app = express();

const patients = [
  { cpr: "2512489996", navn: "Nancy Ann Test Berggren" },
  { cpr: "0107729995", navn: "Max Test Berggren" }
];
```

`patients` er stadig listen i processen. Ikke datalaget. Ikke
`localStorage`. Ikke PostgreSQL endnu.

---

## CORS og JSON-body

Browseren henter stadig fra en anden oprindelse end `localhost:3000`. Behold
headeren fra lektion 11:

```js
app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  next();
});

app.use(express.json());
```

`express.json()` læser JSON i body på `POST`. Uden den middleware er
`req.body` `undefined`.

---

## `GET` og 404

```js
app.get("/api/patients", (req, res) => {
  res.json(patients);
});

app.use((req, res) => {
  res.status(404).json({ error: "not found" });
});

app.listen(3000);
```

Den sidste handler fanger alt, ingen route matchede. Det er jeres gamle
`else` med 404 — ikke en tom liste.

Adfærden skal matche lektion 11, før I tilføjer `POST`:

```mermaid
sequenceDiagram
  participant Browser
  participant Express
  Browser->>Express: GET /api/patients
  Express-->>Browser: 200 og JSON
```

---

## Peg tabellen hertil

`fetch` skal stadig pege på `http://localhost:3000/api/patients`. Felterne
er uændrede. Genstart processen efter omskrivningen, og tjek at JSON i
browseren og rækkerne i tabellen matcher.

---

# Øvelse — Express i `server.js`

---

## Øvelse 1: Fra `http.createServer` til Express

Omskriv `server.js`. `npm install express`. Samme `GET`, samme 404, samme
CORS. Tabellen skal stadig vise listen.

Detaljerne står i [øvelsesarket](oevelser.md).

---

# Pause

---

# Gennemgang — én patient i stien

---

## Én patient i stien

`/api/patients` er hele listen. `/api/patients/2512489996` er én patient.
`:cpr` er et led i stien, ikke en fast tekst. Værdien ligger i
`req.params.cpr`.

```js
app.get("/api/patients/:cpr", (req, res) => {
  const patient = patients.find((p) => p.cpr === req.params.cpr);
  if (!patient) {
    return res.status(404).json({ error: "not found" });
  }
  res.json(patient);
});
```

Routen skal stå over 404-handleren. Findes CPR'en ikke i arrayet, er det
stadig 404 — ikke en tom liste. `GET /api/patients` er uændret.

---

# Quiz — routes og 404

---

## Quiz!

Gå til [/quiz](/quiz) og indtast koden fra tavlen.

**Lektion 13: routes** — `app.get`, `:cpr`, catch-all og listen i hukommelsen.

---

# Øvelse — én patient

---

## Øvelse 2: Én patient via `:cpr`

Tilføj `GET /api/patients/:cpr` over 404-handleren. En kendt CPR giver
patienten. En ukendt CPR giver 404.

Detaljerne står i [øvelsesarket](oevelser.md).

---

# Pause

---

# Gennemgang — `.http`-fil og POST

---

## Hvorfor en `.http`-fil

Browseren er god til `GET`. Den viser JSON pænt og kører jeres `fetch`.

`POST` med en JSON-body kan adresselinjen ikke sende. En **`.http`-fil** i
VS Code sender et request uden HTML. I tester API'et, ikke siden.

Installér extension **REST Client** (Huachao Mao) under Extensions.

Samme protokol som browseren: metode, sti, headers, body.

---

## `GET` fra `api.http`

Lav `api.http` i projektmappen. Med serveren kørende:

```http
### Hele listen
GET http://localhost:3000/api/patients
```

Klik **Send Request** over requestet. Svaret åbner ved siden af:
statuslinjen øverst, så headers, så JSON.

Forkert sti skal stadig give 404 og `{"error":"not found"}` — ikke 200 med
en tom liste.

---

## `POST` — noget skal gemmes

`GET` henter listen. `POST /api/patients` sender én ny patient i body. Serveren
**appender** til `patients` og svarer, at det lykkedes.

```js
app.post("/api/patients", (req, res) => {
  const { cpr, navn } = req.body ?? {};
  if (!cpr || !navn) {
    return res.status(400).json({ error: "cpr og navn skal med" });
  }
  patients.push({ cpr, navn });
  res.status(201).json({ cpr, navn });
});
```

`201 Created` betyder: ressourcen blev oprettet. `400` betyder: body manglede
noget. Det er applikationslagets svar — ikke Express-magi.

Uden JSON-body er `req.body` `undefined`. `?? {}` giver et tomt objekt i
stedet, så requestet får `400` og ikke crasher serveren med `500`.

---

## `POST` med JSON-body

```http
### Opret patient
POST http://localhost:3000/api/patients
Content-Type: application/json

{"cpr":"0201029994","navn":"Ny Test Person"}
```

`###` skiller requests ad. Headeren står under requestlinjen. Den tomme
linje skiller headers fra body — som i selve HTTP-beskeden.

Send derefter `GET` igen. Den nye patient skal stå i arrayet. Genstart
processen — listen er tilbage til de patienter, der står i `server.js`. Den
oprettede patient er væk. At gemme den er lektion 15.

```mermaid
sequenceDiagram
  participant Fil as api.http
  participant Express
  Fil->>Express: POST /api/patients + JSON
  Express-->>Fil: 201 og patient
  Fil->>Express: GET /api/patients
  Express-->>Fil: 200 og hele listen
```

---

## Applikation, ikke database

`push` skriver i hukommelsen i den kørende proces. Filen `server.js` er
stadig ikke tre lag. Applikationslogikken sidder nu i routes i stedet for ét
stort `if`. Tabellen i PostgreSQL kommer i lektion 15. Routen kalder
den i lektion 17.

---

# Quiz — POST og body

---

## Quiz!

Gå til [/quiz](/quiz) og indtast koden fra tavlen.

**Lektion 13: POST** — `express.json`, statuskoder og `.http`-filen.

---

# Pause

---

# Øvelser — POST og projekt

---

## Øvelse 3: POST fra `api.http`

Tilføj `POST /api/patients`. Opret en patient fra `api.http`. Verificér med
`GET` i filen og i browseren.

Detaljerne står i [øvelsesarket](oevelser.md).

---

## Øvelse 4: Tabellen mod jeres server

Tabellen henter fra jeres Express-server. Efter et `POST` fra `api.http` skal en refresh
eller genhentning vise den nye række. Gruppens mockup er stadig tyk klient
på Vercel — men patientlisten til øvelsen kommer fra `localhost`.

Detaljerne står i [øvelsesarket](oevelser.md).
