437 lines
15 KiB
Markdown
437 lines
15 KiB
Markdown
# Les 13 — Externe APIs + Cursor agents + Vercel deploy
|
|
## Slide Overzicht (Klas A — 3 uur fysiek, demo-driven)
|
|
|
|
**Lesvorm:** Tim demonstreert klassikaal. Studenten kijken. Zelf bouwen = huiswerk.
|
|
**Demo-app:** Nieuwe kleine Pokédex (PokéAPI, geen key, visueel)
|
|
**Vervolg op:** Les 12 — Tool Calling
|
|
**Aansluit op:** Les 14 — Agents
|
|
|
|
---
|
|
|
|
## Slide 1: Title
|
|
### Les 13 — Externe APIs + Cursor + Vercel
|
|
|
|
**Visual:**
|
|
- Background: CREAM
|
|
- "Les 13" in BLUE
|
|
- "Externe APIs + Cursor + Vercel" in BLACK
|
|
- Subtitle: "Van localhost naar productie — met Cursor agents en preview deploys"
|
|
|
|
---
|
|
|
|
## Slide 2: Terugblik
|
|
### Waar staan we?
|
|
|
|
**Vorige lessen:**
|
|
- Les 11: AI SDK basics
|
|
- Les 12: Tool Calling
|
|
- Les 13: Agents
|
|
|
|
**Tot nu toe:** alles draaide op `localhost:3000`. Geen wereld eromheen.
|
|
|
|
**Vandaag:**
|
|
- Externe APIs aanroepen (geen LLM nodig, gewoon data ophalen)
|
|
- App naar productie met Vercel
|
|
- Feature branches met Cursor agents (Composer + Background)
|
|
- GitHub Actions CI (lint + build per PR)
|
|
|
|
**Visual:** localhost icoon → cloud icoon met branches eruit.
|
|
|
|
---
|
|
|
|
## Slide 3: Planning
|
|
### Vandaag — 180 minuten
|
|
|
|
| Onderwerp | Duur |
|
|
|-----------|------|
|
|
| Welkom + Terugblik | 10 min |
|
|
| Theorie: Externe APIs in Next.js | 15 min |
|
|
| Theorie: Cursor agents — Composer vs Background | 15 min |
|
|
| Theorie: Vercel preview deploys + GH Actions | 15 min |
|
|
| **Live Demo 1** — Pokédex bouwen met Composer | 30 min |
|
|
| **Live Demo 2** — Deploy naar Vercel productie | 15 min |
|
|
| **Pauze** | 15 min |
|
|
| **Live Demo 3** — Feature branch met Background Agent | 25 min |
|
|
| **Live Demo 4** — GitHub Actions CI | 15 min |
|
|
| Composer vs Background — wanneer welke? | 10 min |
|
|
| Lesopdracht + Huiswerk | 10 min |
|
|
| Vragen + Afsluiting | 5 min |
|
|
|
|
**Format:** Demo-driven, Cursor en browser side-by-side.
|
|
|
|
---
|
|
|
|
## Slide 4: Wat is een externe API?
|
|
### Data van buiten, in jouw app
|
|
|
|
**Het idee:**
|
|
- Andere mensen / bedrijven hebben data of functionaliteit
|
|
- Ze stellen die beschikbaar via HTTP endpoints (REST)
|
|
- Jij doet een `fetch()` en krijgt JSON terug
|
|
|
|
**Voorbeelden:**
|
|
- PokéAPI — Pokemon data (geen key)
|
|
- Open-Meteo — weer (geen key)
|
|
- GitHub API — repos, users, issues
|
|
- Tavily — web search (key nodig)
|
|
- Stripe — betalingen (key + secret)
|
|
|
|
**API keys** horen in environment variables — nooit in je code committen.
|
|
|
|
**Visual:** Diagram: Next.js → fetch → externe API → JSON terug.
|
|
|
|
---
|
|
|
|
## Slide 5: Drie manieren om een API te fetchen in Next.js
|
|
### Static, Server (dynamic), Client — wanneer welke?
|
|
|
|
| | Wanneer gerenderd | Data versheid | Externe API key veilig? | Wanneer kiezen |
|
|
|---|---|---|---|---|
|
|
| **Static** (build-time) | Tijdens `next build` | Bij elke build | Ja, server | Data verandert zelden (blog, marketing, lijst) |
|
|
| **Server / Dynamic** (request-time) | Bij elke request | Altijd vers | Ja, server | Data per user/request anders, of telkens vers nodig |
|
|
| **ISR** (revalidate) | Eerste keer + na X seconden | Periodiek vers | Ja, server | Sweet spot: snel + redelijk vers (Pokédex!) |
|
|
| **Client** (`useEffect`) | In de browser na hydration | Live | **Nee** — sleutel staat in browser | User-interactie, live updates, geen geheim |
|
|
|
|
**Code-verschil = één optie in `fetch`:**
|
|
|
|
```typescript
|
|
// 1. STATIC — gecached forever (default in Next.js!)
|
|
const res = await fetch(URL);
|
|
|
|
// 2. ISR — cache met revalidate
|
|
const res = await fetch(URL, { next: { revalidate: 3600 } });
|
|
|
|
// 3. DYNAMIC — altijd vers
|
|
const res = await fetch(URL, { cache: "no-store" });
|
|
```
|
|
|
|
**Vandaag gebruiken we:** Static voor de Pokédex-lijst, ISR voor detail-pages.
|
|
|
|
---
|
|
|
|
## Slide 6: Cursor — twee soorten agents
|
|
### Composer vs Background
|
|
|
|
| | Composer | Background Agent |
|
|
|---|----------|------------------|
|
|
| Waar draait | Lokaal in je editor | Cursor cloud |
|
|
| Mode | Synchroon — jij wacht | Async — runt zonder jou |
|
|
| Output | Diffs in editor | Branch + PR op GitHub |
|
|
| Goed voor | Pair programming, snelle changes | Welomschreven feature, tijdens andere taak |
|
|
| Aanroep | `Cmd+I` (Mac) / `Ctrl+I` | `Cmd+Shift+P` → Background Agent |
|
|
| Repo nodig | Lokaal | Verbonden met Cursor cloud |
|
|
|
|
**Beide kanten:**
|
|
- Composer: jij stuurt, snel feedback, niet schaalbaar voor lange taken
|
|
- Background: schaalbaar (5 agents tegelijk), maar minder controle in flight
|
|
|
|
**Visual:** Twee tracks naast elkaar — synchroon (jij + composer) vs asynchroon (background agent + jij elders).
|
|
|
|
---
|
|
|
|
## Slide 7: Vercel — productie, preview, environment variables
|
|
### Wat verandert er per omgeving?
|
|
|
|
**Drie omgevingen, drie scopes:**
|
|
|
|
| Scope | Wordt gedeployed bij | URL | Wie ziet het |
|
|
|-------|---------------------|-----|--------------|
|
|
| **Production** | Push naar `main` | `je-app.vercel.app` | Iedereen |
|
|
| **Preview** | Push naar elke andere branch | `je-app-git-{branch}-{user}.vercel.app` | Iedereen met link (delen via PR) |
|
|
| **Development** | Lokaal `pnpm dev` | `localhost:3000` | Alleen jij |
|
|
|
|
**Environment variables per scope:**
|
|
|
|
In Vercel → Project → Settings → Environment Variables zet je per var **drie keer** een waarde:
|
|
|
|
| Var | Production | Preview | Development |
|
|
|-----|------------|---------|-------------|
|
|
| `DATABASE_URL` | prod database | staging database | lokale database |
|
|
| `OPENAI_API_KEY` | echte key | test-key (lage limit) | jouw persoonlijke key |
|
|
| `STRIPE_KEY` | `sk_live_...` | `sk_test_...` | `sk_test_...` |
|
|
| `NEXT_PUBLIC_APP_URL` | je-app.com | preview-url | localhost:3000 |
|
|
|
|
**Waarom is dit belangrijk?**
|
|
- Preview branches mogen NIET stagecoach naar je productie-database schrijven
|
|
- Test API-keys voorkomen kosten/quota-problemen bij experiments
|
|
- Eén branch = één geïsoleerde wereld om in te testen
|
|
|
|
**Cursor Background Agent + Vercel preview = killer combo:**
|
|
Agent opent PR → preview URL automatisch in PR-comment → reviewer test live in browser, geen lokale setup nodig.
|
|
|
|
---
|
|
|
|
## Slide 8: GitHub Actions CI
|
|
### Lint + build per PR
|
|
|
|
**Waarom:**
|
|
- Voor merge weet je: code lint clean én build slaagt
|
|
- Voorkomt "werkte op mijn laptop"
|
|
- Background Agent doet PR → CI draait automatisch → groene check of feedback
|
|
|
|
**Minimaal `.github/workflows/ci.yml`:**
|
|
|
|
```yaml
|
|
name: CI
|
|
on:
|
|
pull_request:
|
|
branches: [main]
|
|
push:
|
|
branches: [main]
|
|
|
|
jobs:
|
|
check:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: pnpm/action-setup@v3
|
|
with: { version: 9 }
|
|
- uses: actions/setup-node@v4
|
|
with: { node-version: 20, cache: pnpm }
|
|
- run: pnpm install
|
|
- run: pnpm lint
|
|
- run: pnpm build
|
|
```
|
|
|
|
**Tijd per CI-run:** ~1-2 min op een kleine Next.js app.
|
|
|
|
---
|
|
|
|
## Slide 9: Wat we vandaag bouwen
|
|
### Pokédex — Next.js + PokéAPI
|
|
|
|
**Doel:** Een mini-Pokédex om de hele pipeline te oefenen.
|
|
|
|
**Stack:**
|
|
- Next.js 16 + TypeScript + Tailwind + Shadcn
|
|
- PokéAPI (geen key, gratis, geen rate-limit bij normaal gebruik)
|
|
- Cursor (Composer + Background Agent)
|
|
- GitHub (repo + Actions)
|
|
- Vercel (productie + preview deploys)
|
|
|
|
**Features die we bouwen vandaag:**
|
|
|
|
| Feature | Met | Branch |
|
|
|---------|-----|--------|
|
|
| Pokédex list (eerste 151) | Composer | main |
|
|
| Detail page per Pokemon | Composer | main |
|
|
| Search met filter | Background Agent | feature/search |
|
|
| Type-filter chips | Background Agent | feature/type-filter |
|
|
|
|
**Visual:** Folder-tree + GitHub branch-diagram + Vercel URLs.
|
|
|
|
---
|
|
|
|
## Slide 10: LIVE DEMO 1 — Pokédex met Composer + rendering modes
|
|
### ~30 min
|
|
|
|
**Wat ik laat zien:**
|
|
1. `pnpm create next-app pokedex --typescript --tailwind --app`
|
|
2. Open in Cursor
|
|
3. **Composer (`Cmd+I`)**: "Bouw een lijst-pagina met de eerste 151 Pokémon van PokéAPI als statische pagina. Gebruik Tailwind cards. De fetch moet static zijn — geen revalidate."
|
|
4. Composer maakt: `app/page.tsx` met `fetch(URL)` (static) + map + cards
|
|
5. `pnpm dev` — werkt
|
|
6. **Composer**: "Voeg detail-pagina toe op /pokemon/[name] met sprite + types + stats. Gebruik ISR met revalidate van 3600 seconden."
|
|
7. Composer maakt: `app/pokemon/[name]/page.tsx` met `{ next: { revalidate: 3600 } }`
|
|
8. **Bewijs in de browser:** open detail-pagina, refresh — direct geladen (statisch). Verander URL → andere Pokémon → ook snel (ISR cache).
|
|
9. **Show de Network tab:** geen calls naar PokéAPI vanuit browser, alles server.
|
|
10. **Bonus:** maak één pagina met `cache: "no-store"` (dynamic) zodat studenten alle drie de modi gezien hebben.
|
|
|
|
**Belangrijk om uit te leggen:**
|
|
- Composer is een TAB in Cursor — niet hetzelfde als Chat
|
|
- Multi-file edits zichtbaar als diffs — je accepteert per file
|
|
- Terminal commands vragen toestemming
|
|
- De rendering-mode is één optie in `fetch()` — verder verandert je code niet
|
|
|
|
**Visual:** Cursor screenshot met Composer panel.
|
|
|
|
---
|
|
|
|
## Slide 11: LIVE DEMO 2 — Deploy naar Vercel + Environment variables
|
|
### ~20 min
|
|
|
|
**Wat ik laat zien:**
|
|
1. **GitHub:** new repo `pokedex` — public
|
|
2. **Lokaal:**
|
|
```bash
|
|
git init
|
|
git add . && git commit -m "Initial Pokédex"
|
|
git branch -M main
|
|
git remote add origin https://github.com/USER/pokedex.git
|
|
git push -u origin main
|
|
```
|
|
3. **Vercel:** Add New → Import Git Repository → kies `pokedex` → Deploy
|
|
4. Wachten 60-90s op build → Productie URL — werkt!
|
|
5. **Environment Variables demo:** voeg een var toe in `app/page.tsx`:
|
|
```tsx
|
|
<p>Omgeving: {process.env.NEXT_PUBLIC_APP_ENV}</p>
|
|
```
|
|
6. **Vercel → Settings → Environment Variables:**
|
|
- `NEXT_PUBLIC_APP_ENV` = `production` → vinkje bij Production
|
|
- `NEXT_PUBLIC_APP_ENV` = `preview` → vinkje bij Preview
|
|
- Lokaal: `.env.local` → `NEXT_PUBLIC_APP_ENV=development`
|
|
7. Redeploy → productie URL toont "production"
|
|
8. Maak feature branch `chore/banner`, push → preview URL toont "preview"
|
|
9. Lokaal `pnpm dev` → toont "development"
|
|
|
|
**Wat studenten moeten zien:**
|
|
- Push to main = productie deploy
|
|
- Push to andere branch = preview deploy (eigen URL)
|
|
- Per omgeving andere env-waarden
|
|
- Voor secrets: vinkje **alleen** bij Production (preview-key gebruiken in preview!)
|
|
|
|
---
|
|
|
|
## Slide 12: Pauze
|
|
### 15 minuten
|
|
|
|
---
|
|
|
|
## Slide 13: LIVE DEMO 3 — Feature branch + Background Agent
|
|
### ~25 min
|
|
|
|
**Wat ik laat zien:**
|
|
1. **Cursor:** `Cmd+Shift+P` → "Open Background Agent"
|
|
2. **Verbind** repo aan Cursor cloud (eenmalig — accepteren in browser)
|
|
3. **Prompt aan Background Agent:**
|
|
> "Maak een nieuwe branch `feature/search`. Voeg een zoekbalk toe bovenaan de homepage. Wanneer iemand typt, filter de Pokémon-lijst op naam. Gebruik client-side state. Push de branch + open een PR met titel 'Add search bar'."
|
|
4. **Background Agent gaat aan de slag** — Tim laat zien hoe je 'm volgt in het Cursor panel
|
|
5. **~3-5 minuten later:** PR verschijnt op GitHub
|
|
6. **Vercel** comment in PR: preview URL → klik → live preview!
|
|
7. **Demo:** zoeken werkt op preview URL
|
|
8. **Code review** in GitHub UI: wat heeft de agent gedaan?
|
|
9. **Merge** → main → productie deploy
|
|
|
|
**Tweede prompt — parallel:**
|
|
> "Maak branch `feature/type-filter`. Voeg chips toe bij elk type (fire, water, ...) om te filteren."
|
|
|
|
Beide branches kunnen tegelijk draaien.
|
|
|
|
**Visual:** Cursor Background Agent panel + GitHub PR + Vercel preview URL.
|
|
|
|
---
|
|
|
|
## Slide 14: LIVE DEMO 4 — GitHub Actions CI
|
|
### ~15 min
|
|
|
|
**Wat ik laat zien:**
|
|
1. **Vraag aan Composer:**
|
|
> "Voeg een GitHub Actions workflow toe: lint + build moeten slagen op PR's naar main."
|
|
2. Composer maakt `.github/workflows/ci.yml`
|
|
3. Push naar nieuwe branch `chore/add-ci`
|
|
4. Open PR → GitHub Actions tab → workflow draait
|
|
5. **Demo failing CI:** introduceer typo (`<dvi>`), push, zie rode X
|
|
6. Fix met Composer ("repareer de TypeScript build error in de PR"), push, zie groene check
|
|
7. **Branch protection:** main beschermen — PR's mogen pas mergen als CI groen is
|
|
|
|
**Waarom belangrijk:**
|
|
- Background Agents kunnen lint-errors maken — CI vangt dit op
|
|
- Voor je merge: weet je dat het op een schone runner ook werkt
|
|
- Geen "werkt op mijn laptop"-discussies
|
|
|
|
---
|
|
|
|
## Slide 15: Composer vs Background Agent
|
|
### Wanneer welke?
|
|
|
|
| Scenario | Tool |
|
|
|----------|------|
|
|
| Snelle wijziging tijdens coden | Composer |
|
|
| Complex refactor over meerdere files | Composer (kun je begeleiden) |
|
|
| Onbekend gebied — wil zien wat agent doet | Composer |
|
|
| Welomschreven feature, kan op de achtergrond | Background Agent |
|
|
| Parallel werken aan 3 features | 3x Background Agent |
|
|
| Tijdens vergadering een PR voorbereiden | Background Agent |
|
|
| Repo nog niet in Cursor cloud | Composer |
|
|
|
|
**Mentale model:**
|
|
- **Composer = pair programming** — jij + AI samen aan dezelfde plek
|
|
- **Background Agent = delegeren** — je geeft taak, gaat iets anders doen, komt terug
|
|
|
|
**Risico bij Background Agent:**
|
|
- Agent kan vastlopen op rare config — debugging is moeilijker
|
|
- Verbruikt credits (Cursor Pro of Business)
|
|
- Te vage prompts → matige PR's. Specifiek zijn helpt.
|
|
|
|
---
|
|
|
|
## Slide 16: Lesopdracht + Huiswerk
|
|
### Pokédex zelf bouwen + deploy
|
|
|
|
**Lesopdracht (in-class, 30 min):**
|
|
- Eigen Pokédex repo opzetten (zelfde setup als demo)
|
|
- 1 feature met Composer toevoegen
|
|
- Push naar GitHub + connect Vercel
|
|
- Productie URL openen — werkt
|
|
|
|
**Huiswerk (voor Les 16):**
|
|
- **A:** Feature branch met Background Agent (1 feature, jouw keuze) → preview URL delen
|
|
- **B:** GitHub Actions CI (lint + build) in werking
|
|
- **C:** Branch protection — main mag pas merge na groene CI
|
|
- **D:** `DEPLOY.md` met:
|
|
- Productie URL + 1 preview URL
|
|
- Reflectie: Composer vs Background — wanneer welke werkte beter?
|
|
- 1 voorbeeld waar Background Agent verbluffend goed of slecht was
|
|
|
|
**Bonus:**
|
|
- Eigen externe API integreren (Open-Meteo, GitHub, jouw keuze)
|
|
- Vercel environment vars demo (verschillende waarde in preview vs prod)
|
|
|
|
---
|
|
|
|
## Slide 17: Volgende les + Afsluiting
|
|
### Vragen?
|
|
|
|
**Vandaag gezien:**
|
|
- Externe API integratie in Server Components
|
|
- Static / ISR / Dynamic / Client — vier rendering modes
|
|
- Cursor Composer voor synchrone changes
|
|
- Cursor Background Agent voor async features
|
|
- Vercel productie + preview per branch
|
|
- Environment variables per omgeving (production / preview / development)
|
|
- GitHub Actions CI (lint + build)
|
|
|
|
**Volgende les (Les 14): Agents**
|
|
- LLM in een loop met tools, autonoom 20-50 stappen
|
|
- `ToolLoopAgent`, `stopWhen`, `prepareStep`
|
|
- Research-agent from scratch
|
|
- Wanneer wel/niet agents gebruiken
|
|
|
|
**Vragen? Feedback?**
|
|
|
|
---
|
|
|
|
## Slide Summary
|
|
|
|
| # | Title | Type |
|
|
|---|-------|------|
|
|
| 1 | Title | Opening |
|
|
| 2 | Terugblik | Recap |
|
|
| 3 | Planning | 180-min |
|
|
| 4 | Externe APIs | Theorie |
|
|
| 5 | Externe API code | Theorie |
|
|
| 6 | Cursor — Composer vs Background | Theorie |
|
|
| 7 | Vercel preview deploys | Theorie |
|
|
| 8 | GitHub Actions CI | Theorie |
|
|
| 9 | Wat we bouwen | Intro demo |
|
|
| 10 | **LIVE DEMO 1** — Pokédex + Composer | Demo |
|
|
| 11 | **LIVE DEMO 2** — Vercel deploy | Demo |
|
|
| 12 | Pauze | Break |
|
|
| 13 | **LIVE DEMO 3** — Background Agent + preview | Demo |
|
|
| 14 | **LIVE DEMO 4** — GitHub Actions CI | Demo |
|
|
| 15 | Wanneer welke Cursor-mode | Reflectie |
|
|
| 16 | Lesopdracht + Huiswerk | Praktijk |
|
|
| 17 | Afsluiting + Les 13 preview | Closing |
|
|
|
|
---
|
|
|
|
## Bronnen
|
|
|
|
- **PokéAPI:** https://pokeapi.co/
|
|
- **Next.js fetching:** https://nextjs.org/docs/app/building-your-application/data-fetching
|
|
- **Cursor agents:** https://cursor.com/product
|
|
- **Vercel preview deployments:** https://vercel.com/docs/deployments/preview-deployments
|
|
- **Vercel environment variables:** https://vercel.com/docs/environment-variables
|
|
- **GitHub Actions for Next.js:** https://nextjs.org/docs/app/building-your-application/deploying
|
|
- **GitHub branch protection:** https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches
|