Hoppa till huvudinnehåll

Kom igång med SvelteKit och Fetch API 🚀

Modulsmål 🎯

Efter denna modul ska du kunna:

  • ✅ Sätta upp och köra igång ett SvelteKit-projekt
  • ✅ Använda fetch() för att hämta data från API:er
  • ✅ Skicka data till API:er med POST-requests
  • ✅ Förstå grunderna i hur klient-server kommunikation fungerar
Byggvidare på dina Svelte-kunskaper

Du har redan arbetat med Svelte för statiska hemsidor. Nu tar vi steget till SvelteKit - ett fullstack-ramverk som låter oss bygga både frontend och backend! 🌟

Steg 1: Skapa ditt SvelteKit-projekt 🛠️

Setup och första intryck

Din uppgift 1: Skapa projektet och utforska strukturen

# Kör dessa kommandon och observera vad som händer
npm create svelte@latest mitt-sveltekit-projekt
cd mitt-sveltekit-projekt
npm install
npm run dev

Reflektera:

  • Vilka filer skapades som du inte sett i vanlig Svelte?
  • Vad händer när du besöker http://localhost:5173?
  • Jämför src/routes/ med en vanlig Svelte-app - vad är skillnaden?
Navigationsutmaning! 🧭

Kom ihåg att alltid vara i rätt mapp när du kör kommandon! Använd cd <mappnamn> för att navigera och cd .. för att gå upp en nivå. Kör pwd (Mac/Linux) eller cd (Windows) för att se var du är.

Steg 2: Förstå Fetch API:et genom experimentation 🌐

Utforska med ett känt API

Din uppgift 2: Experimentera först med fetch i browser console

Öppna developer tools (F12) och kör detta i console:

// Testa detta i browser console först - vad händer?
fetch('https://jsonplaceholder.typicode.com/posts?_limit=3')
.then(response => /* Vad ska stå här? */)
.then(data => console.log(data));

Frågor att besvara:

  • Vad returnerar fetch() direkt?
  • Varför behöver vi .then() två gånger?
  • Vad händer om du tar bort ?_limit=3?

Första SvelteKit-implementering

Din uppgift 3: Skapa din första fetch i SvelteKit

Ersätt innehållet i src/routes/+page.svelte:

<script>
import { onMount } from 'svelte';

let posts = [];
let loading = /* Vad ska denna börja med? boolean */;
let error = null;

onMount(async () => {
// Din uppgift: Implementera fetch-logiken här
// 1. Sätt loading till rätt värde
// 2. Fetcha från 'https://jsonplaceholder.typicode.com/posts?_limit=5'
// 3. Hantera response (kommer du ihåg från console-testet?)
// 4. Sätt posts-variabeln
// 5. Hantera fel med try/catch
// 6. Sätt loading till false när klart

try {
// Din kod här

} catch (err) {
// Vad ska hända vid fel?

} finally {
// Vad ska alltid hända?

}
});
</script>

<h1>Mina första API-anrop! 📡</h1>

<!-- Din uppgift: Implementera conditional rendering -->
{#if /* när ska vi visa loading? */}
<p>Laddar data...</p>
{:else if /* när ska vi visa fel? */}
<p class="error">Fel: {error}</p>
{:else}
<div class="posts">
<!-- Din uppgift: Loopa genom posts och visa titel + body -->
<!-- Tips: använd {#each posts as post} -->

</div>
{/if}

<style>
/* Din uppgift: Lägg till styling för .post och .error */

</style>

Frågor för reflektion:

  • Varför använder vi onMount istället för att fetcha direkt i script?
  • Vad är skillnaden mellan let loading = true och let loading = false?
  • Varför behöver vi try/catch/finally?

Steg 3: Skicka data med POST - Guided Discovery 📤

Först: Förstå vad POST gör

Din uppgift 4: Experimentera med POST i browser console

// Testa detta först - vad skickar vi?
const newPost = {
title: 'Min titel',
body: 'Mitt innehåll',
userId: 1
};

// Din uppgift: Fyll i de tomma delarna
fetch('https://jsonplaceholder.typicode.com/posts', {
method: /* Vilken HTTP-metod? */,
headers: {
'Content-Type': /* Vilken content-type för JSON? */,
},
body: /* Hur konverterar vi objektet till sträng? */
})
.then(response => response.json())
.then(data => console.log('Skapad:', data));

Implementera i SvelteKit

Din uppgift 5: Lägg till ett formulär för att skapa inlägg

Lägg till detta EFTER ditt befintliga innehåll i +page.svelte:

<script>
// Befintlig kod här...

// Nya variabler för formuläret - vilka behöver vi?
let newPostTitle = '';
let newPostBody = '';
let isSubmitting = /* börjar vi med att submitta? */;

async function createPost() {
// Din uppgift: Implementera denna funktion
// 1. Validera att titel och body inte är tomma
// 2. Sätt isSubmitting till true
// 3. Skicka POST-request (använd samma struktur som console-testet)
// 4. Om framgång: lägg till det nya inlägget i posts-arrayen
// 5. Rensa formuläret
// 6. Hantera fel
// 7. Sätt isSubmitting till false

// Validering först:
if (/* kontrollera om titel eller body är tomma */) {
alert('Fyll i både titel och innehåll!');
return;
}

// Din implementation här:

}
</script>

<!-- Befintligt innehåll här... -->

<section class="create-post">
<h2>Skapa nytt inlägg ✍️</h2>

<!-- Din uppgift: Skapa formuläret -->
<!-- Tips: använd on:submit|preventDefault för att förhindra page reload -->
<form on:submit|preventDefault={/* vilken funktion? */}>
<div>
<label for="title">Titel:</label>
<!-- Bind input till newPostTitle variabeln -->
<input
id="title"
type="text"
bind:value={/* vilken variabel? */}
placeholder="Skriv en titel..."
disabled={/* när ska input vara disabled? */}
/>
</div>

<div>
<label for="body">Innehåll:</label>
<!-- Samma för textarea -->
<textarea
id="body"
bind:value={/* vilken variabel? */}
placeholder="Skriv ditt inlägg..."
disabled={/* när ska textarea vara disabled? */}
></textarea>
</div>

<!-- Knapp som visar olika text beroende på om vi submittar -->
<button type="submit" disabled={/* när ska knappen vara disabled? */}>
{/* Conditional text: "Skapar..." eller "Skapa inlägg" */}
</button>
</form>
</section>

<style>
/* Befintlig CSS... */

/* Din uppgift: Styling för formuläret */
.create-post {
/* Bakgrund, padding, margin? */
}

.create-post div {
/* Spacing mellan form-element? */
}

.create-post input,
.create-post textarea {
/* Styling för inputs? */
}

.create-post button {
/* Styling för knapp? */
}

.create-post button:disabled {
/* Hur ska disabled knapp se ut? */
}
</style>

Steg 4: Problemlösning och fördjupning 🔧

Vanliga utmaningar - Lös själv först!

Utmaning 1: Command not found

# Om du får detta fel:
npm: command not found

Din uppgift: Vad kan detta bero på? Hur löser du det?

Utmaning 2: Port redan används

# Om du får:
Error: Port 5173 is already in use

Din uppgift: Vad betyder detta? Hitta minst 2 sätt att lösa det.

Utmaning 3: Data visas inte Symtom: Formuläret skickas men inlägget syns inte i listan. Din uppgift: Debug steg för steg:

  1. Öppna Network tab i developer tools
  2. Vad visar POST-requesten?
  3. Logga newPost innan du lägger till den i posts
  4. Kontrollera att du uppdaterar posts-arrayen korrekt

Experimentera vidare

Din uppgift 6: Implementera dessa förbättringar själv

  1. Delete-funktionalitet

    • Lägg till en "Ta bort"-knapp på varje inlägg
    • Använd DELETE-request till https://jsonplaceholder.typicode.com/posts/${id}
    • Ta bort inlägget från posts-arrayen
  2. Edit-funktionalitet

    • Lägg till "Redigera"-knapp
    • Visa redigeringsformulär
    • Använd PUT-request för att uppdatera
  3. Bättre felhantering

    • Visa specifika felmeddelanden
    • Retry-funktion vid nätverksfel
    • Loading state per inlägg

Reflektion: Vilken av dessa var svårast? Varför?

Viktiga koncept att reflektera över 🧠

Async/Await vs Promises

Din uppgift: Skriv om din fetch-kod med .then() istället för async/await. Vilken föredrar du och varför?

State Management

Frågor att fundera på:

  • Varför behöver vi let posts = [] istället för const?
  • Vad händer om två API-anrop sker samtidigt?
  • Hur skulle du hantera konflikter mellan lokal och server-data?

User Experience

Utvärdera din app:

  • Hur länge väntar användaren på data?
  • Vad händer vid långsamma anslutningar?
  • Känns appen responsiv?

Debugging Workshop 🔍

Din uppgift 7: Introduktion av buggar att hitta och fixa

Lägg till dessa buggar i din kod och försök hitta dem:

<script>
// Bug 1: Glöm await
onMount(() => {
fetch('...') // Vad händer utan await?
.then(...)
});

// Bug 2: Fel variabelnamn
let newPostTitle = '';
// Men i formuläret: bind:value={newTitle}

// Bug 3: Glöm finally-block
try {
// fetch...
} catch (err) {
error = err.message;
// Vad händer om loading aldrig sätts till false?
}
</script>

Frågor: Hur upptäcker du varje bug? Vilka verktyg hjälper dig?

Nästa steg och utmaning 🚀

Din uppgift 8: Förbered för nästa modul

I nästa modul ska vi bygga våra egna API-endpoints. Fundera på:

  1. Vad är skillnaden mellan att använda andras API:er och att bygga egna?
  2. Vilka fördelar skulle det ge att kontrollera servern själv?
  3. Vilka nya utmaningar tror du det medför?

Experiment: Hitta ett annat gratis API (t.ex. från denna lista) och implementera det i din app.

Du har byggt ditt första SvelteKit-interface! 💪

Nu förstår du grunderna i klient-server kommunikation. I nästa modul bygger vi server-sidan också!

Sammanfattning av viktiga lärdomar

Efter denna modul bör du förstå:

  • SvelteKit-projektstruktur och hur den skiljer sig från vanlig Svelte
  • Fetch API för att kommunicera med servrar
  • Asynkron programmering med async/await
  • State management i Svelte-komponenter
  • Felhantering vid nätverksanrop
  • Formulärhantering och användarinteraktion

Nästa: Vi bygger våra egna API-endpoints med +server.ts!