לדלג לתוכן

4.6 בקשות HTTP פתרון

פתרון - בקשות HTTP

פתרון תרגיל 1

async function getUser(id) {
    try {
        const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);

        if (!response.ok) {
            throw new Error(`User not found (status ${response.status})`);
        }

        const user = await response.json();
        console.log(`${user.name} - ${user.email}`);
        return user;
    } catch (error) {
        console.error("Error:", error.message);
    }
}

await getUser(1);   // "Leanne Graham - Sincere@april.biz"
await getUser(999); // "Error: User not found (status 404)"

פתרון תרגיל 2

<div id="posts"></div>
async function displayPosts() {
    const container = document.getElementById("posts");
    container.textContent = "Loading...";

    try {
        const response = await fetch("https://jsonplaceholder.typicode.com/posts");

        if (!response.ok) {
            throw new Error(`HTTP error: ${response.status}`);
        }

        const posts = await response.json();
        container.textContent = ""; // clear loading message

        posts.forEach(post => {
            const card = document.createElement("div");
            card.className = "post-card";
            card.innerHTML = `
                <h3>${post.title}</h3>
                <p>${post.body}</p>
            `;
            container.appendChild(card);
        });
    } catch (error) {
        container.textContent = `Error: ${error.message}`;
    }
}

displayPosts();

פתרון תרגיל 3

<form id="postForm">
    <input type="text" id="title" placeholder="Title" required>
    <textarea id="body" placeholder="Content" required></textarea>
    <button type="submit">Create Post</button>
</form>
<div id="result"></div>
async function createPost(postData) {
    try {
        const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(postData)
        });

        if (!response.ok) {
            throw new Error(`Failed to create post (status ${response.status})`);
        }

        const created = await response.json();
        console.log("Created:", created);
        return created;
    } catch (error) {
        console.error("Error:", error.message);
    }
}

document.getElementById("postForm").addEventListener("submit", async (e) => {
    e.preventDefault();

    const title = document.getElementById("title").value;
    const body = document.getElementById("body").value;

    const result = await createPost({ title, body, userId: 1 });

    if (result) {
        document.getElementById("result").textContent =
            `Post created with id: ${result.id}`;
    }
});

פתרון תרגיל 4

async function searchPosts(userId, limit) {
    try {
        const params = new URLSearchParams({ userId });

        if (limit) {
            params.append("_limit", limit);
        }

        const response = await fetch(
            `https://jsonplaceholder.typicode.com/posts?${params}`
        );

        if (!response.ok) {
            throw new Error(`Search failed (status ${response.status})`);
        }

        const posts = await response.json();

        console.log(`Found ${posts.length} posts by user ${userId}:`);
        posts.forEach(post => {
            console.log(`  - ${post.title}`);
        });

        return posts;
    } catch (error) {
        console.error("Error:", error.message);
    }
}

await searchPosts(1);    // all posts by user 1
await searchPosts(1, 3); // first 3 posts by user 1

פתרון תרגיל 5

const BASE_URL = "https://jsonplaceholder.typicode.com";

const PostService = {
    async getAll() {
        try {
            const response = await fetch(`${BASE_URL}/posts`);
            if (!response.ok) {
                throw new Error(`Failed to get posts (${response.status})`);
            }
            return await response.json();
        } catch (error) {
            console.error("getAll error:", error.message);
            throw error;
        }
    },

    async getById(id) {
        try {
            const response = await fetch(`${BASE_URL}/posts/${id}`);
            if (!response.ok) {
                throw new Error(`Post ${id} not found (${response.status})`);
            }
            return await response.json();
        } catch (error) {
            console.error("getById error:", error.message);
            throw error;
        }
    },

    async create(data) {
        try {
            const response = await fetch(`${BASE_URL}/posts`, {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(data)
            });
            if (!response.ok) {
                throw new Error(`Failed to create post (${response.status})`);
            }
            return await response.json();
        } catch (error) {
            console.error("create error:", error.message);
            throw error;
        }
    },

    async update(id, data) {
        try {
            const response = await fetch(`${BASE_URL}/posts/${id}`, {
                method: "PUT",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(data)
            });
            if (!response.ok) {
                throw new Error(`Failed to update post ${id} (${response.status})`);
            }
            return await response.json();
        } catch (error) {
            console.error("update error:", error.message);
            throw error;
        }
    },

    async delete(id) {
        try {
            const response = await fetch(`${BASE_URL}/posts/${id}`, {
                method: "DELETE"
            });
            if (!response.ok) {
                throw new Error(`Failed to delete post ${id} (${response.status})`);
            }
            console.log(`Post ${id} deleted`);
        } catch (error) {
            console.error("delete error:", error.message);
            throw error;
        }
    }
};

// testing
const posts = await PostService.getAll();
console.log(posts.length); // 100

const post = await PostService.getById(1);
console.log(post.title);

const newPost = await PostService.create({ title: "Test", body: "Body", userId: 1 });
console.log(newPost.id); // 101

await PostService.update(1, { title: "Updated", body: "New body", userId: 1 });
await PostService.delete(1);

פתרון תרגיל 6

א. fetchWithTimeout:

async function fetchWithTimeout(url, options = {}, timeout = 5000) {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);

    try {
        const response = await fetch(url, {
            ...options,
            signal: controller.signal
        });
        clearTimeout(timeoutId);
        return response;
    } catch (error) {
        clearTimeout(timeoutId);
        if (error.name === "AbortError") {
            throw new Error(`Request timed out after ${timeout}ms`);
        }
        throw error;
    }
}

// testing
try {
    const response = await fetchWithTimeout(
        "https://jsonplaceholder.typicode.com/posts",
        {},
        3000
    );
    const data = await response.json();
    console.log(`Got ${data.length} posts`);
} catch (error) {
    console.error(error.message);
}

ב. fetchLatest:

let currentController = null;

async function fetchLatest(endpoint) {
    // cancel previous request if it exists
    if (currentController) {
        currentController.abort();
    }

    currentController = new AbortController();
    const myController = currentController; // save reference

    try {
        const response = await fetch(
            `https://jsonplaceholder.typicode.com${endpoint}`,
            { signal: myController.signal }
        );

        if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
        }

        const data = await response.json();
        console.log("Got result for:", endpoint);
        return data;
    } catch (error) {
        if (error.name === "AbortError") {
            console.log("Cancelled:", endpoint);
            return null;
        }
        throw error;
    }
}

פתרון תרגיל 7

async function getUserWithPosts(userId) {
    try {
        const [userResponse, postsResponse] = await Promise.all([
            fetch(`https://jsonplaceholder.typicode.com/users/${userId}`),
            fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`)
        ]);

        if (!userResponse.ok) {
            throw new Error(`User not found (${userResponse.status})`);
        }
        if (!postsResponse.ok) {
            throw new Error(`Failed to get posts (${postsResponse.status})`);
        }

        const [user, posts] = await Promise.all([
            userResponse.json(),
            postsResponse.json()
        ]);

        return { user, posts };
    } catch (error) {
        console.error("Error:", error.message);
        throw error;
    }
}

const result = await getUserWithPosts(1);
console.log(result.user.name);    // "Leanne Graham"
console.log(result.posts.length); // 10

פתרון תרגיל 8

function createApiClient(baseUrl) {
    let authToken = null;

    async function request(endpoint, options = {}) {
        const { method = "GET", body, timeout = 10000 } = options;

        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), timeout);

        const headers = {
            "Content-Type": "application/json",
            "Accept": "application/json"
        };

        if (authToken) {
            headers["Authorization"] = `Bearer ${authToken}`;
        }

        const config = {
            method,
            headers,
            signal: controller.signal
        };

        if (body) {
            config.body = JSON.stringify(body);
        }

        try {
            const response = await fetch(`${baseUrl}${endpoint}`, config);
            clearTimeout(timeoutId);

            if (!response.ok) {
                const errorData = await response.json().catch(() => ({}));
                const error = new Error(errorData.message || `HTTP ${response.status}`);
                error.status = response.status;
                throw error;
            }

            if (response.status === 204) {
                return null;
            }

            return await response.json();
        } catch (error) {
            clearTimeout(timeoutId);
            if (error.name === "AbortError") {
                throw new Error("Request timed out");
            }
            throw error;
        }
    }

    return {
        setToken(token) {
            authToken = token;
        },

        get(endpoint) {
            return request(endpoint);
        },

        post(endpoint, body) {
            return request(endpoint, { method: "POST", body });
        },

        put(endpoint, body) {
            return request(endpoint, { method: "PUT", body });
        },

        delete(endpoint) {
            return request(endpoint, { method: "DELETE" });
        }
    };
}

// testing
const client = createApiClient("https://jsonplaceholder.typicode.com");

client.setToken("my-secret-token");

const posts = await client.get("/posts");
console.log(posts.length); // 100

const newPost = await client.post("/posts", { title: "Hi", body: "World", userId: 1 });
console.log(newPost.id); // 101

await client.put("/posts/1", { title: "Updated", body: "New", userId: 1 });
await client.delete("/posts/1");