# Lektion 17 — Forberedelse

I lektion 13 bor patientlisten i et array i `server.js`. I lektion 15 lagde I
de samme patienter i en tabel i Neon. I dag forbinder vi de to: routen henter
og gemmer i tabellen, og listen husker, når serveren genstarter.
Forberedelsen er, hvordan koden deles i lag, hvordan Node taler med
PostgreSQL, og et lille script, der henter fra din egen Neon-database.

Forberedelsen er ca. 70 minutter.

## 1. Lag i koden (~30 min)

### Læs først: route og repository

I lektion 11 delte vi et system i tre lag: præsentation, applikation og
data. Indtil nu har applikation og data siddet i samme fil: routen i
`server.js` både besluttede, hvad der skulle svares, og holdt listen.

Når data flytter ind i en database, deler vi koden i to dele:

- **Routen** taler HTTP. Den læser requestet, tjekker at felterne er der,
  og vælger statuskode: `200`, `201`, `400`, `500`.
- **Repositoryet** taler SQL. Det er de få funktioner, der kender tabellen —
  fx `hentPatienter()` og `opretPatient(cpr, navn)`. Det er det eneste sted
  i koden, hvor der står SQL.

Routen ved ikke, at der findes en tabel. Den kalder bare en funktion og får
rækker tilbage. Repositoryet ved ikke, at der findes HTTP. Skifter I
database, retter I ét sted. Skal I finde en SQL-fejl, ved I, hvor I skal
kigge.

Et repository er ikke et bibliotek eller et framework. Det er en fil med
funktioner, I selv skriver. I dag hedder den `patients.js`.

Databasen svarer ikke med det samme. Funktionerne i repositoryet er derfor
`async`, og routen venter med `await` — samme mønster som `fetch` i lektion 7.

### Derefter: to lectures på freeCodeCamp

1. [What Is SQL Injection, and What Are Some Ways to Prevent It?](https://www.freecodecamp.org/learn/relational-databases-v9/lecture-working-with-sql/what-is-sql-injection-and-what-are-some-ways-to-prevent-it)
   (modulet **SQL and Bash**). Fokusér på, hvordan brugerens input bliver
   til SQL, når det sættes ind med `+`, og på **parameterized queries**.
   Afsnittet om databaserettigheder kan du skimme.
2. [What are HTTP Response Status Codes?](https://www.freecodecamp.org/learn/back-end-development-and-apis-v9/lecture-understanding-error-handling-and-health-checks/what-are-http-response-status-codes)
   Fokusér på `200`, `201`, `400`, `404` og `500`. Dem bruger vi i dag. 1xx
   og 3xx kan du springe over.

### Til sidst: forespørgsler i node-postgres

**[node-postgres: Queries](https://node-postgres.com/features/queries)**

Læs de to første afsnit, **Text only** og **Parameterized query**. Spring
**Query config object** over.

`pg` er den pakke, Node bruger til at tale med PostgreSQL. Her ser du
parameterized queries i den syntaks, I skal skrive: SQL'en har pladsholdere —
`$1`, `$2` — og værdierne sendes ved siden af, i et array.

Eksemplerne bruger `client.query`. Vi bruger `pool.query`. Siden siger selv,
at de virker ens.

## 2. Hent fra din egen database (~40 min)

Du skriver et kort script, der henter patienterne fra dit
Neon-projekt `lektion15`. Arbejd i en ny mappe, `l17-forberedelse`. Ikke i
gruppens projekt.

1. Opret mappen, og installér `pg`:

```bash
npm init -y
npm install pg
```

2. Find connection-stringen til dit **eget** projekt `lektion15` i Neon:
   **Connect** → **Copy snippet**. Det er samme dialog som i lektion 15,
   øvelse 3.
3. Lav filen `.env` i mappen i VS Code — ikke med `>` i PowerShell, det giver
   forkert tegnsæt. Én linje, og variablen skal hedde præcis `DATABASE_URL`.
   Ret `sslmode=require` til `sslmode=verify-full` i strengen — ellers
   skriver `pg` en lang sikkerhedsadvarsel:

```text
DATABASE_URL=postgresql://neondb_owner:…@…neon.tech/neondb?sslmode=verify-full&channel_binding=require
```

4. Lav filen `.gitignore` med to linjer, så hverken passwordet eller
   pakkerne kommer i git:

```text
.env
node_modules/
```

5. Lav `hent.js`:

```js
const { Pool } = require("pg");

const pool = new Pool({ connectionString: process.env.DATABASE_URL });

async function main() {
  const alle = await pool.query("SELECT cpr, navn FROM patients ORDER BY id");
  console.log(alle.rows);

  const max = await pool.query(
    "SELECT navn FROM patients WHERE cpr = $1",
    ["0107729995"]
  );
  console.log(max.rows);

  await pool.end();
}

main();
```

6. Kør det:

```bash
node --env-file=.env hent.js
```

Du skal se de fem testpatienter som et array, og derefter `[ { navn: 'Max
Test Berggren' } ]`. `--env-file=.env` lægger linjen fra `.env` i
`process.env`, før scriptet starter.

7. Ret CPR'en i `$1`-arrayet til en, der ikke findes. Kør igen. Hvad får du
   tilbage — en fejl eller et tomt array?

## Når du er færdig

Du skal kunne forklare:

- forskellen på en route og et repository, og hvilken af dem der kender SQL
- hvorfor `$1` og et array er bedre end at sætte CPR'en ind i SQL-teksten med
  `+`
- hvad `.env` og `--env-file` gør, og hvorfor `.env` står i `.gitignore`
- at `pool.query` returnerer et objekt, hvor rækkerne ligger i `.rows`

Og du skal have kørt `hent.js` mod din egen database.

At lægge repositoryet ind i gruppens `server.js`, `POST` og fejlkoder tager
vi i timen.

## Praktisk

- Har du ikke `patients` i dit Neon-projekt `lektion15`, så kør `CREATE
  TABLE` og de fem `INSERT` fra [lektion 15, øvelse 1 og 2](../lektion15/oevelser.md)
  i SQL-editoren først.
- `ECONNREFUSED` betyder, at `pg` ikke fik nogen connection-string og prøver
  din egen maskine. Du har glemt `--env-file=.env`, linjen hedder ikke
  præcis `DATABASE_URL=`, eller filen er lavet i PowerShell med `>`.
- `node: .env: not found`: filen findes ikke i den mappe, du står i — eller
  den hedder `.env.txt`.
- `password authentication failed`: strengen i `.env` er forkert. Kopiér den
  igen med **Copy snippet**.
- Hav connection-stringen til **gruppens** database klar til timen. Den fik
  I i lektion 15, øvelse 3.
- `server.js` skal blive stående, som den er fra lektion 13.
