Files
novi-lessons/Les17-Externe-APIs/Les17-Slide-Overzicht.md
2026-06-03 16:58:25 +02:00

11 KiB

Les 17 — Externe APIs in diepte

Slide Overzicht (Klas A — 3 uur fysiek, demo-driven)

Lesvorm: Tim demonstreert klassikaal. Studenten kijken. Zelf bouwen = huiswerk. Demo-app: Subscription-dashboard (Stripe Checkout + Resend email) Vervolg op: Les 16 — MCP servers Aansluit op: Les 18 — Supabase Auth + RLS


Slide 1: Title

Les 17 — Externe APIs in diepte

Visual: "Les 17" BLUE, "Externe APIs in diepte" BLACK, subtitle "OAuth, webhooks, Stripe en Resend — productie-patronen"


Slide 2: Terugblik

Waar staan we?

Lessen 11-16:

  • AI SDK, tool calling, agents, RAG, Cursor+Vercel deploy, MCP

Externe APIs deden we al in Les 15 (PokéAPI): simpel, geen key, GET requests. Productie is anders.

Vandaag — de echte wereld:

  • Login met Google/GitHub (OAuth)
  • Iemand doet een betaling — server moet dat weten (webhooks)
  • Betaalde APIs zoals Stripe en Resend
  • Wat als de API faalt? Retry-logic
  • Hoe doe je dat veilig en netjes?

Slide 3: Planning

Vandaag — 180 minuten

Onderwerp Duur
Terugblik + API-types 15 min
Theorie: OAuth basics 20 min
Theorie: Webhooks + verifying 20 min
Live Demo 1 — Stripe Checkout integratie 25 min
Live Demo 2 — Webhook ontvangen + verify 25 min
Pauze 15 min
Live Demo 3 — Resend transactional email 25 min
Live Demo 4 — Rate limit + retry pattern 15 min
Productie checklist 10 min
Lesopdracht + Huiswerk 10 min

Slide 4: Drie soorten externe API integratie

Welke heb je nodig?

Type Voorbeeld Wat moet je weten
Simple fetch PokéAPI, Open-Meteo URL + JSON parsing (Les 15)
API key in header OpenAI, Tavily, Anthropic Env vars, server-side fetch
OAuth flow Google login, GitHub Redirect dance, tokens, sessies
Webhook Stripe, GitHub, Slack POST endpoint, signature verify

Vandaag focus op de laatste twee — daar komen 80% van productie-API-bugs vandaan.


Slide 5: OAuth — wat en waarom

Login met Google / GitHub / etc.

Het probleem: je wilt dat gebruikers inloggen zonder zelf wachtwoorden te beheren.

OAuth flow (kort):

1. User klikt "Login met GitHub"
2. Redirect naar github.com/login/oauth/authorize
3. User logt in op GitHub + geeft toestemming
4. GitHub redirect terug naar JOUW app met code
5. JOUW server exchanged code voor access_token
6. JOUW server haalt user-data op met token
7. JOUW server zet sessie / cookie

In Next.js — drie populaire libraries:

  • Auth.js (NextAuth v5) — meest gebruikt
  • Better-Auth — moderne challenger, eenvoudiger
  • Clerk — paid, alles inclusief

Voor dit vak: Auth.js — open source, gratis, werkt overal.


Slide 6: Webhooks — wat en waarom

Externe service belt JOUW app

Het probleem: soms moet je weten wanneer iets gebeurt op een externe service.

Voorbeeld Stripe:

  • User doet betaling op Stripe Checkout
  • Stripe verwerkt betaling (zou kunnen falen!)
  • Stripe stuurt POST request naar JOUW webhook URL
  • Jouw server update database, stuurt email, etc.

Webhook = jouw HTTP endpoint dat door externe service wordt aangeroepen.

Cruciaal: signature verification

Zonder verificatie kan iedereen je webhook URL aanroepen met fake data.

// Stripe doet dit zo:
const sig = request.headers.get("stripe-signature");
const event = stripe.webhooks.constructEvent(
  body, sig, process.env.STRIPE_WEBHOOK_SECRET
);
// Throws als signature niet klopt

Slide 7: Wat we vandaag bouwen

Subscription-dashboard

Mini-app: Premium subscription met Stripe + email confirmaties.

Tech:

  • Next.js 16
  • Stripe (test mode — geen echt geld)
  • Resend (transactional email — gratis tier 3000/maand)
  • ngrok of localhost.run voor lokaal webhook testen

Flow:

[Pricing page] → [Stripe Checkout] → [Webhook] → [Database + Email]

Endpoints we bouwen:

  • POST /api/checkout — start Stripe sessie
  • POST /api/webhook/stripe — ontvang Stripe events
  • POST /api/email — verzend Resend mail (intern aangeroepen)

Slide 8: LIVE DEMO 1 — Stripe Checkout

~25 min

Wat ik laat zien:

  1. Stripe account opzetten (test mode)
  2. Pricing page met "Subscribe" button
  3. app/api/checkout/route.ts — maak Checkout session
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function POST(req: Request) {
  const { priceId, email } = await req.json();
  const session = await stripe.checkout.sessions.create({
    mode: "subscription",
    line_items: [{ price: priceId, quantity: 1 }],
    customer_email: email,
    success_url: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${process.env.APP_URL}/pricing`,
  });
  return Response.json({ url: session.url });
}
  1. Client redirect naar session.url
  2. Test in browser met Stripe test cards (4242 4242 4242 4242)
  3. Stripe Dashboard — sessie zichtbaar, betaling staat als "complete"

Slide 9: LIVE DEMO 2 — Webhook ontvangen

~25 min

Wat ik laat zien:

  1. Webhook secret ophalen van Stripe Dashboard
  2. app/api/webhook/stripe/route.ts:
import { headers } from "next/headers";

export async function POST(req: Request) {
  const body = await req.text();          // RAW body, niet json()
  const sig = headers().get("stripe-signature")!;

  let event;
  try {
    event = stripe.webhooks.constructEvent(
      body, sig, process.env.STRIPE_WEBHOOK_SECRET!
    );
  } catch (err) {
    return new Response("Webhook signature failed", { status: 400 });
  }

  if (event.type === "checkout.session.completed") {
    const session = event.data.object;
    await supabase.from("subscriptions").insert({
      customer_email: session.customer_email,
      stripe_session_id: session.id,
      status: "active",
    });
  }
  return Response.json({ received: true });
}
  1. Lokaal testen: stripe listen --forward-to localhost:3000/api/webhook/stripe
  2. Stripe CLI geeft webhook secret terug — in .env.local
  3. Doe een test-checkout — zie webhook binnenkomen in CLI én database update

Belangrijk: req.text() voor RAW body — niet req.json(). Signature wordt over bytes berekend.


Slide 10: Pauze

15 min


Slide 11: LIVE DEMO 3 — Resend email

~25 min

Wat ik laat zien:

  1. Resend account, API key, eigen domain (of onboarding@resend.dev voor demo)
  2. pnpm add resend react-email
  3. Email template als React component:
// emails/WelcomeEmail.tsx
export function WelcomeEmail({ name }: { name: string }) {
  return (
    <div style={{ fontFamily: "sans-serif" }}>
      <h1>Welkom {name}!</h1>
      <p>Bedankt voor je aanmelding bij Premium.</p>
    </div>
  );
}
  1. Verzend in webhook handler:
import { Resend } from "resend";
import { WelcomeEmail } from "@/emails/WelcomeEmail";

const resend = new Resend(process.env.RESEND_API_KEY!);

await resend.emails.send({
  from: "onboarding@resend.dev",
  to: session.customer_email!,
  subject: "Welkom bij Premium!",
  react: WelcomeEmail({ name: session.customer_email!.split("@")[0] }),
});
  1. Test checkout → webhook → mail komt aan
  2. Resend dashboard — email zichtbaar in logs, status delivered

Slide 12: LIVE DEMO 4 — Rate limit + retry

~15 min

Wat ik laat zien:

Probleem: externe APIs kunnen falen. Wat doe je?

Pattern 1 — Exponential backoff retry:

async function retry<T>(fn: () => Promise<T>, attempts = 3): Promise<T> {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fn();
    } catch (err) {
      if (i === attempts - 1) throw err;
      await new Promise(r => setTimeout(r, 2 ** i * 1000));
    }
  }
  throw new Error("unreachable");
}

const data = await retry(() =>
  fetch("https://api.example.com/data").then(r => r.json())
);

Pattern 2 — Rate limit met Upstash Ratelimit:

import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, "10s"),
});

// In API route
const { success } = await ratelimit.limit(userId);
if (!success) return new Response("Too many requests", { status: 429 });

Beide patronen zijn cruciaal voor productie. Niet doen = service crash bij verkeerd gedrag.


Slide 13: Productie checklist

Voordat je live gaat

API keys:

  • ✓ Test-keys voor preview, prod-keys voor productie
  • ✓ Vercel scoping per environment (Les 15)
  • ✓ Rotate keys eens per kwartaal

Webhooks:

  • ✓ Signature verification ALTIJD
  • ✓ Idempotency — zelfde event 2x ontvangen = OK
  • ✓ Log alle webhook payloads (helpt bij debug)
  • ✓ Return 200 snel — verwerking async

Errors:

  • ✓ Exponential backoff retry voor transient fails
  • ✓ Rate limit eigen endpoints
  • ✓ Monitor met Sentry / LogRocket / Vercel Analytics

Security:

  • ✓ Keys nooit in client-bundle (geen NEXT_PUBLIC_)
  • ✓ Webhook endpoints accepteren alleen verified signatures
  • ✓ User-input validatie (Zod)

Slide 14: Lesopdracht + Huiswerk

Eigen externe API integreren

Lesopdracht (30 min):

  • Stripe test account opzetten
  • Pricing page + Checkout endpoint
  • Doe een test-betaling met test card
  • Geen webhook nog — alleen success_url demo

Huiswerk (~2 uur, voor Les 18):

  • A: Webhook handler + signature verify
  • B: Resend transactional email na betaling
  • C: Retry logic voor externe API call
  • D: APIS.md met:
    • Welke externe APIs jouw app gebruikt
    • Hoe webhooks getest worden (Stripe CLI of ngrok screenshots)
    • Voorbeeld van een failed call + hoe afgevangen
    • Eindopdracht-toepassing: welke API ga jij integreren

Bonus: OAuth login met GitHub/Google via Auth.js


Slide 15: Volgende les + Afsluiting

Vragen?

Vandaag gezien:

  • Drie soorten externe API integratie
  • OAuth flow basics
  • Webhooks ontvangen + signature verify
  • Stripe Checkout in productie-patroon
  • Resend transactional email
  • Rate limit + retry
  • Productie checklist

Volgende les (Les 18 — laatste!): Supabase Auth + RLS

  • Multi-user apps met login
  • Magic link / password / social
  • RLS policies — per-user data isolation
  • Protected routes + middleware
  • Combo van alles wat we geleerd hebben

Vragen?


Slide Summary

# Title Type
1 Title Opening
2 Terugblik Recap
3 Planning 180-min
4 3 soorten API integratie Theorie
5 OAuth basics Theorie
6 Webhooks + verifying Theorie
7 Wat we bouwen Intro
8 DEMO 1 — Stripe Checkout Demo
9 DEMO 2 — Webhook ontvangen Demo
10 Pauze Break
11 DEMO 3 — Resend email Demo
12 DEMO 4 — Rate limit + retry Demo
13 Productie checklist Reflectie
14 Lesopdracht + Huiswerk Praktijk
15 Afsluiting Closing

Bronnen