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
- 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.
- Example: You fetch posts with
- 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!
- Resource-Based: Everything is a “resource” (posts, users, tags) with a unique URL.
- Example:
https://myblog.com/api/posts/1is post #1.
- Example:
- Client-Server Architecture: The client (your app) and server (data storage) are separate, talking only through the REST API.
- Example: Your app uses
fetchto ask for posts; the server doesn’t care what the app looks like.
- Example: Your app uses
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:
fetchsends 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:
fetchsends 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:
PUTtargets 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:
PATCHtargets 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:
DELETEtargets 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 usesfetchto 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
- Clear Endpoints
- Good:
fetch("/api/posts"),fetch("/api/posts/1") - Bad:
fetch("/api/getPosts")(GET is implied!) - Why: Keeps URLs resource-focused and intuitive.
- Good:
- Handle Errors
- Example: Check
response.okin everyfetchcall. - Why: Catches issues like 404 (post not found) early.
- Example: Check
- 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.
- Keep Payloads Lean
- Good: Send only
{ title: "New Post" }in POST. - Bad: Sending the entire app state!
- Why: Avoids overfetching or slow requests.
- Good: Send only
Advantages
- Scalability: Statelessness lets any server handle
fetchrequests—great for our blog’s growth. - Interoperability:
fetchworks in browsers and Node.js (with polyfills), talking to any REST API. - Maintainability: Uniform methods make debugging
fetchcalls straightforward.
Disadvantages – And Fixes
- 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").
- Problem:
- Stateless Overhead:
- Problem: Every
fetchrepeats auth tokens. - Fix: Add headers:
fetch(url, { headers: { Authorization: "Bearer token" } }).
- Problem: Every
- Multiple Requests:
- Problem: Need posts and comments? Two
fetchcalls. - Fix: Fetch combined data:
fetch("/api/posts/1?include=comments").
- Problem: Need posts and comments? Two
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.