Skip to main content
Svelte Fundamentals
CHAPTER 16 Beginner

Working with JSON and REST APIs

Updated: May 18, 2026
5 min read

# CHAPTER 16

Working with JSON and REST APIs

1. Chapter Introduction

REST APIs are the backbone of modern web applications. In this chapter, we implement complete CRUD (Create, Read, Update, Delete) operations against a REST API using Svelte, building a Blog Management application as our project.

2. Learning Objectives

  • Implement GET, POST, PUT, PATCH, DELETE requests.
  • Parse and display JSON responses.
  • Build a complete CRUD service module.
  • Handle API errors per operation.
  • Build a Blog Management Application.

3. REST Methods Reference

text
123456
GET    /posts       → List all posts
GET    /posts/1     → Get post #1
POST   /posts       → Create new post
PUT    /posts/1     → Replace post #1 completely
PATCH  /posts/1     → Update specific fields of post #1
DELETE /posts/1     → Delete post #1

4. API Service Module

javascript
12345678910111213141516171819
// src/lib/services/blogApi.js
const BASE_URL = 'https://jsonplaceholder.typicode.com';

async function request(endpoint, options = {}) {
  const response = await fetch(`${BASE_URL}${endpoint}`, {
    headers: { 'Content-Type': 'application/json', ...options.headers },
    ...options
  });
  if (!response.ok) throw new Error(`API Error: ${response.status}`);
  return response.json();
}

export const blogApi = {
  getPosts: () => request('/posts?_limit=10'),
  getPost: (id) => request(`/posts/${id}`),
  createPost: (data) => request('/posts', { method: 'POST', body: JSON.stringify(data) }),
  updatePost: (id, data) => request(`/posts/${id}`, { method: 'PUT', body: JSON.stringify(data) }),
  deletePost: (id) => request(`/posts/${id}`, { method: 'DELETE' })
};

5. Blog List with CRUD

svelte
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
<!-- BlogApp.svelte -->
<script>
  import { onMount } from &#039;svelte';
  import { blogApi } from &#039;$lib/services/blogApi.js';

  let posts = [];
  let loading = true;
  let error = &#039;';
  let editingPost = null;
  let showForm = false;
  let form = { title: &#039;', body: '' };

  onMount(async () => {
    try { posts = await blogApi.getPosts(); }
    catch (e) { error = e.message; }
    finally { loading = false; }
  });

  async function createPost() {
    try {
      const newPost = await blogApi.createPost({ ...form, userId: 1 });
      posts = [newPost, ...posts];
      resetForm();
    } catch (e) { error = e.message; }
  }

  async function updatePost() {
    try {
      const updated = await blogApi.updatePost(editingPost.id, { ...editingPost, ...form });
      posts = posts.map(p => p.id === editingPost.id ? updated : p);
      resetForm();
    } catch (e) { error = e.message; }
  }

  async function deletePost(id) {
    if (!confirm(&#039;Delete this post?')) return;
    try {
      await blogApi.deletePost(id);
      posts = posts.filter(p => p.id !== id);
    } catch (e) { error = e.message; }
  }

  function startEdit(post) {
    editingPost = post;
    form = { title: post.title, body: post.body };
    showForm = true;
  }

  function resetForm() {
    form = { title: &#039;', body: '' };
    editingPost = null;
    showForm = false;
  }

  function handleSubmit() {
    if (editingPost) updatePost();
    else createPost();
  }
</script>

<div class="blog-app">
  <div class="header">
    <h1>📝 Blog Manager</h1>
    <button on:click={() => { showForm = !showForm; resetForm(); }}>
      {showForm ? &#039;✕ Cancel' : '+ New Post'}
    </button>
  </div>

  {#if error}<div class="error">{error}</div>{/if}

  {#if showForm}
    <form on:submit|preventDefault={handleSubmit} class="post-form">
      <h2>{editingPost ? &#039;Edit Post' : 'New Post'}</h2>
      <input bind:value={form.title} placeholder="Title" required />
      <textarea bind:value={form.body} placeholder="Content..." rows="4" required></textarea>
      <div class="form-actions">
        <button type="button" on:click={resetForm}>Cancel</button>
        <button type="submit">{editingPost ? &#039;Update' : 'Create'}</button>
      </div>
    </form>
  {/if}

  {#if loading}
    <p>Loading posts...</p>
  {:else}
    <div class="post-list">
      {#each posts as post (post.id)}
        <article class="post-card">
          <h3>{post.title}</h3>
          <p>{post.body.slice(0, 120)}...</p>
          <div class="actions">
            <button on:click={() => startEdit(post)}>✏️ Edit</button>
            <button class="danger" on:click={() => deletePost(post.id)}>🗑️ Delete</button>
          </div>
        </article>
      {/each}
    </div>
  {/if}
</div>

6. Common Mistakes

  • Not cloning objects before editing: Always create a copy { ...post } when editing. Modifying a post directly mutates the array element.
  • Optimistic updates vs server confirmation: The blog above waits for the server response before updating the UI. For better UX, consider optimistic updates (update UI first, rollback on error).

7. MCQs

Question 1

What HTTP method creates a new resource?

Question 2

What HTTP method completely replaces a resource?

Question 3

What HTTP method partially updates a resource?

Question 4

How do you send JSON in a fetch request body?

Question 5

What status code indicates successful creation?

Question 6

What status code indicates no content (successful delete)?

Question 7

How do you update an item in a reactive Svelte array after PUT?

Question 8

How do you remove an item from a reactive array after DELETE?

Question 9

Why create a centralized API service module?

Question 10

What is the difference between a network error and an HTTP error?

8. Interview Questions

  • Q: Implement a centralized API service that automatically includes auth tokens in every request.
  • Q: What is optimistic updating? What are its benefits and risks?

9. Summary

REST API integration in Svelte follows clean patterns: a centralized service module handles all HTTP logic, onMount triggers initial data loading, and reactive array updates (map, filter, spread) keep the UI synchronized with server state. The Blog Manager project demonstrates a complete production CRUD pattern.

10. Next Chapter Recommendation

Our app is functional — now let's make it beautiful and delightful! In Chapter 17: Svelte Transitions and Animations, we add fade, slide, scale, and custom animations that bring our UI to life.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·