# 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

Omgeving: {process.env.NEXT_PUBLIC_APP_ENV}

``` 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 (``), 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