15 KiB
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:
// 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:
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:
pnpm create next-app pokedex --typescript --tailwind --app- Open in Cursor
- 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." - Composer maakt:
app/page.tsxmetfetch(URL)(static) + map + cards pnpm dev— werkt- Composer: "Voeg detail-pagina toe op /pokemon/[name] met sprite + types + stats. Gebruik ISR met revalidate van 3600 seconden."
- Composer maakt:
app/pokemon/[name]/page.tsxmet{ next: { revalidate: 3600 } } - Bewijs in de browser: open detail-pagina, refresh — direct geladen (statisch). Verander URL → andere Pokémon → ook snel (ISR cache).
- Show de Network tab: geen calls naar PokéAPI vanuit browser, alles server.
- 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:
- GitHub: new repo
pokedex— public - Lokaal:
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 - Vercel: Add New → Import Git Repository → kies
pokedex→ Deploy - Wachten 60-90s op build → Productie URL — werkt!
- Environment Variables demo: voeg een var toe in
app/page.tsx:<p>Omgeving: {process.env.NEXT_PUBLIC_APP_ENV}</p> - Vercel → Settings → Environment Variables:
NEXT_PUBLIC_APP_ENV=production→ vinkje bij ProductionNEXT_PUBLIC_APP_ENV=preview→ vinkje bij Preview- Lokaal:
.env.local→NEXT_PUBLIC_APP_ENV=development
- Redeploy → productie URL toont "production"
- Maak feature branch
chore/banner, push → preview URL toont "preview" - 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:
- Cursor:
Cmd+Shift+P→ "Open Background Agent" - Verbind repo aan Cursor cloud (eenmalig — accepteren in browser)
- 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'." - Background Agent gaat aan de slag — Tim laat zien hoe je 'm volgt in het Cursor panel
- ~3-5 minuten later: PR verschijnt op GitHub
- Vercel comment in PR: preview URL → klik → live preview!
- Demo: zoeken werkt op preview URL
- Code review in GitHub UI: wat heeft de agent gedaan?
- 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:
- Vraag aan Composer:
"Voeg een GitHub Actions workflow toe: lint + build moeten slagen op PR's naar main."
- Composer maakt
.github/workflows/ci.yml - Push naar nieuwe branch
chore/add-ci - Open PR → GitHub Actions tab → workflow draait
- Demo failing CI: introduceer typo (
<dvi>), push, zie rode X - Fix met Composer ("repareer de TypeScript build error in de PR"), push, zie groene check
- 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.mdmet:- 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