PresentationInteractive, narrated presentation of the section content.

ContentDetailed description of the section content.

Motivation: Why REST APIs Matter

Imagine you’re using our blogging app. You tap a button to see posts tagged “coding,” write a new post about your latest project, or delete an old draft—all from your browser or phone. How does this happen so seamlessly? The answer is REST APIs—Representational State Transfer Application Programming Interfaces. They’re the digital couriers that shuttle your requests to the server and bring back the data, all over HTTP, the same system that powers the web.

REST APIs are everywhere—think social media feeds, online stores, or even the projects you’ll build in this course. Today, we’ll explore their foundation, how to use them with the fetch API on the client side, and best practices to make them work for our blogging app. Here’s a fun question: Ever thought an app “knows” what you did last time you used it? With REST, it doesn’t—and that’s a superpower we’ll unpack soon!

Busting a Misconception

Some of you might think REST APIs are just random URLs you click. Not true! They’re a structured way to manage resources—like blog posts—using specific rules and HTTP methods, and we’ll use fetch to talk to them from the client.


Section 1: The Foundation of REST APIs

REST APIs are built on simplicity and a few core ideas that make them powerful. Let’s lay the groundwork with our blogging app in mind.

Key Principles

  1. Statelessness: Every request you send—like “Show me coding posts”—must include all the info the server needs. The server doesn’t store session data between requests, making it scalable.
    • Example: You fetch posts with fetch("https://myblog.com/api/posts?tag=coding")—the server starts fresh each time.
  2. Uniform Interface: REST uses standard HTTP methods—GET, POST, PUT, DELETE—that always do the same job, keeping things predictable.
    • Example: GET fetches, POST creates—consistent every time!
  3. Resource-Based: Everything is a “resource” (posts, users, tags) with a unique URL.
    • Example: https://myblog.com/api/posts/1 is post #1.
  4. Client-Server Architecture: The client (your app) and server (data storage) are separate, talking only through the REST API.
    • Example: Your app uses fetch to ask for posts; the server doesn’t care what the app looks like.

Surprise Twist

You might think the server remembers your last request. Nope! Statelessness means it forgets after each one—surprising, but it’s why REST handles millions of users so well.


Section 2: Using REST APIs with Fetch – Hands-On Examples

Let’s put REST to work in our blogging app using the fetch API, a built-in JavaScript tool for making HTTP requests from the client. We’ll use TypeScript for type safety and walk through each HTTP method with complete, working examples.

Setting Up the Basics

First, here’s the Post interface we’ll use across all examples:

interface Post {
  id: number;
  title: string;
  tag: string;
  content?: string; // Optional for some operations
}

1. GET – Fetching Data

  • Purpose: Retrieve posts from the server.
  • Simple Example: Get all posts.
async function fetchAllPosts(): Promise<Post[]> {
  const response = await fetch("https://myblog.com/api/posts");
  if (!response.ok) throw new Error("Failed to fetch posts");
  const posts: Post[] = await response.json();
  return posts;
}

fetchAllPosts()
  .then(posts => console.log(posts))
  .catch(error => console.error(error));
  • How It Works:
    • fetch sends a GET request to /api/posts.
    • The server responds with JSON, like [{"id": 1, "title": "Learning REST", "tag": "coding"}].
  • Advanced Example: Filter posts by tag.
async function fetchPostsByTag(tag: string): Promise<Post[]> {
  const response = await fetch(`https://myblog.com/api/posts?tag=${tag}`);
  if (!response.ok) throw new Error(`Failed to fetch ${tag} posts`);
  const posts: Post[] = await response.json();
  return posts;
}

fetchPostsByTag("coding")
  .then(posts => console.log(posts))
  .catch(error => console.error(error));
  • How It Works: Adds a query parameter (?tag=coding) to filter results.

2. POST – Creating Data

  • Purpose: Add a new post as an admin.
async function createPost(newPost: Post): Promise<{ id: number; message: string }> {
  const response = await fetch("https://myblog.com/api/posts", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(newPost),
  });
  if (!response.ok) throw new Error("Failed to create post");
  const result = await response.json();
  return result;
}

const newPost: Post = { id: 0, title: "My API Journey", tag: "coding", content: "So cool!" };
createPost(newPost)
  .then(result => console.log(result)) // e.g., { id: 2, message: "Post created" }
  .catch(error => console.error(error));
  • How It Works:
    • fetch sends a POST request with a JSON payload.
    • The server saves it and returns a new ID.

3. PUT – Updating Data

  • Purpose: Update an existing post.
async function updatePost(postId: number, updatedPost: Post): Promise<{ message: string }> {
  const response = await fetch(`https://myblog.com/api/posts/${postId}`, {
    method: "PUT",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(updatedPost),
  });
  if (!response.ok) throw new Error("Failed to update post");
  const result = await response.json();
  return result;
}

const updates: Partial<Post> = { title: "Learning REST – Updated" };
updatePost(1, updates)
  .then(result => console.log(result)) // e.g., { message: "Post updated" }
  .catch(error => console.error(error));
  • How It Works:
    • PUT targets a specific post (/posts/1) and sends updated fields.

4. PATCH – Updating Partial Data

  • Purpose: Update portions of existing post. Allows to send less data.
async function updatePost(postId: number, updatedPost: Partial<Post>): Promise<{ message: string }> {
  const response = await fetch(`https://myblog.com/api/posts/${postId}`, {
    method: "PATCH",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(updatedPost),
  });
  if (!response.ok) throw new Error("Failed to update post");
  const result = await response.json();
  return result;
}

const updates: Partial<Post> = { title: "Learning REST – Updated" };
updatePost(1, updates)
  .then(result => console.log(result)) // e.g., { message: "Post updated" }
  .catch(error => console.error(error));
  • How It Works:
    • PATCH targets a specific post (/posts/1) and sends updated fields.
    • Partial<Post> allows flexibility—update only what’s needed.

4. DELETE – Removing Data

  • Purpose: Delete a post.
async function deletePost(postId: number): Promise<{ message: string }> {
  const response = await fetch(`https://myblog.com/api/posts/${postId}`, {
    method: "DELETE",
  });
  if (!response.ok) throw new Error("Failed to delete post");
  const result = await response.json();
  return result;
}

deletePost(1)
  .then(result => console.log(result)) // e.g., { message: "Post deleted" }
  .catch(error => console.error(error));
  • How It Works:
    • DELETE targets a specific post and removes it.
    • The server confirms with a success message.

Expanding the Example

Imagine a user flow:

  • Fetch all posts with fetchAllPosts().
  • Filter to “coding” posts with fetchPostsByTag("coding").
  • Add a new post with createPost().
  • Update its title with updatePost().
  • Delete an old draft with deletePost(). Each step uses fetch to talk to the REST API, building a complete app experience.

Section 3: Best Practices for REST APIs with Fetch

Using REST APIs with fetch is powerful, but doing it right takes some tips. Let’s explore best practices and pitfalls, tied to our blogging app.

Best Practices

  1. Clear Endpoints
    • Good: fetch("/api/posts"), fetch("/api/posts/1")
    • Bad: fetch("/api/getPosts") (GET is implied!)
    • Why: Keeps URLs resource-focused and intuitive.
  2. Handle Errors
    • Example: Check response.ok in every fetch call.
    • Why: Catches issues like 404 (post not found) early.
  3. Use HTTP Status Codes
    • Example: Expect 201 for POST success, 200 for GET.
    • With Fetch: if (response.status === 201) console.log("Created!").
    • Why: Gives clear feedback on what happened.
  4. Keep Payloads Lean
    • Good: Send only { title: "New Post" } in POST.
    • Bad: Sending the entire app state!
    • Why: Avoids overfetching or slow requests.

Advantages

  • Scalability: Statelessness lets any server handle fetch requests—great for our blog’s growth.
  • Interoperability: fetch works in browsers and Node.js (with polyfills), talking to any REST API.
  • Maintainability: Uniform methods make debugging fetch calls straightforward.

Disadvantages – And Fixes

  1. Overfetching/Underfetching:
    • Problem: fetch("/api/posts/1") might return too much or too little.
    • Fix: Use query params: fetch("/api/posts/1?fields=title,tag").
  2. Stateless Overhead:
    • Problem: Every fetch repeats auth tokens.
    • Fix: Add headers: fetch(url, { headers: { Authorization: "Bearer token" } }).
  3. Multiple Requests:
    • Problem: Need posts and comments? Two fetch calls.
    • Fix: Fetch combined data: fetch("/api/posts/1?include=comments").

Advanced Fetch Example

Filter posts by tag and date:

async function fetchFilteredPosts(tag: string, date: string): Promise<Post[]> {
  const response = await fetch(`https://myblog.com/api/posts?tag=${tag}&date=${date}`);
  if (!response.ok) throw new Error("Failed to fetch filtered posts");
  const posts: Post[] = await response.json();
  return posts;
}

fetchFilteredPosts("coding", "2025-04")
  .then(posts => console.log(posts))
  .catch(error => console.error(error));
  • Why It’s Great: Combines filters for efficiency, showing REST’s flexibility with fetch.

Conclusion: Mastering REST APIs with Fetch

REST APIs are the glue that connects our blogging app’s client to its server, and fetch is your tool to make it happen. Here’s what to remember:

  • Foundation: REST is stateless, resource-based, and uses HTTP methods—perfect for scalable apps.
  • Usage: With fetch, you can GET posts, POST new ones, PUT updates, and DELETE drafts—all from the client.
  • Best Practices: Write clear endpoints, handle errors, use status codes, and keep requests lean for smooth performance.

In our blogging app, fetch powers everything from browsing posts to managing them as an admin. As you build projects in this course, you’ll use REST APIs and fetch to create dynamic, real-world apps. Next time you load a webpage or save a post, think: “That’s REST and fetch at work!”—and now, you can make it work too!

No hints available.

Discuss with OthersAsk questions, share your thoughts, and discuss with other learners.

Loading discussion ...
Setup
React Fundamentals
Next.js
Advanced React
Databases
React Hooks
Authentication and Authorisation
APIs
CI/CD and DevOps
Testing React
Advanced Topics