Obafemi Emmanuel

JavaScript Fetch API & HTTP Requests

Published 3 months ago

The Fetch API is a modern and powerful way to handle HTTP requests in JavaScript. It simplifies data fetching from APIs and replaces the older XMLHttpRequest approach with a cleaner, promise-based syntax. In this blog, we will explore how to fetch data, handle JSON responses, compare XMLHttpRequest with Fetch API, use async/await, and manage errors effectively.


1. Fetching Data from APIs (fetch())

The fetch() function allows you to request resources from a URL and returns a Promise that resolves into a Response object.


Basic Syntax:

fetch('https://jsonplaceholder.typicode.com/posts')
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error('Error:', error));

Explanation:

  • fetch(url): Sends a request to the specified URL.
  • .then(response => response.json()): Converts the response to JSON.
  • .then(data => console.log(data)): Processes and displays the data.
  • .catch(error => console.error('Error:', error)): Catches any errors that occur during the fetch process.

2. Handling JSON Data

Most modern APIs return data in JSON format. You need to convert the response into a JavaScript object before using it.


Example:

fetch('https://jsonplaceholder.typicode.com/users')
    .then(response => {
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
        return response.json();
    })
    .then(users => users.forEach(user => console.log(user.name)))
    .catch(error => console.error('Error fetching users:', error));


If the response of fetch() is not JSON, attempting to call .json() on it will result in an error. To handle this, you should first check the Content-Type of the response or attempt different parsing methods depending on the expected format.


Handling Non-JSON Responses

Here are some ways to properly handle responses that may not be in JSON format:

1. Check Content-Type Before Parsing

javascript
CopyEdit
async function fetchData(url) {
    try {
        let response = await fetch(url);

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

        const contentType = response.headers.get("content-type");

        if (contentType.includes("application/json")) {
            let data = await response.json();
            console.log("JSON Data:", data);
        } else if (contentType.includes("text/html")) {
            let text = await response.text();
            console.log("HTML Data:", text);
        } else if (contentType.includes("application/xml") || contentType.includes("text/xml")) {
            let text = await response.text();
            console.log("XML Data:", text);
        } else {
            console.log("Unknown Content-Type:", contentType);
        }

    } catch (error) {
        console.error("Error fetching data:", error);
    }
}

fetchData("https://example.com/data");

2. Try Different Parsing Methods

If you are unsure about the response format, you can attempt different parsing methods:

javascript
CopyEdit
async function fetchData(url) {
    try {
        let response = await fetch(url);
        if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);

        let data;
        try {
            data = await response.json(); // Attempt to parse as JSON
        } catch {
            data = await response.text(); // Fallback to text
        }

        console.log("Response Data:", data);

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

fetchData("https://example.com/data");


Sending Parameters with fetch()


You can send parameters with fetch() in several ways depending on the request type: GET, POST, PUT, DELETE, etc.


1. Sending Parameters in a GET Request

For GET requests, parameters are appended to the URL as query strings:


Example: Sending Query Parameters in a GET Request

javascript
CopyEdit
async function fetchWithParams() {
    const params = new URLSearchParams({
        userId: 1,
        status: "active",
    });

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

    let data = await response.json();
    console.log(data);
}

fetchWithParams();
  • The URLSearchParams object converts parameters into a valid query string.
  • The final URL will look like:
arduino
CopyEdit
https://jsonplaceholder.typicode.com/posts?userId=1&status=active

2. Sending Parameters in a POST Request

For POST (or any other method like PUT, DELETE), parameters are sent in the request body.


Example: Sending JSON Data in a POST Request

javascript
CopyEdit
async function sendPostRequest() {
    let response = await fetch("https://jsonplaceholder.typicode.com/posts", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify({
            title: "Fetch API Guide",
            body: "This is a post request using fetch.",
            userId: 1,
        }),
    });

    let data = await response.json();
    console.log(data);
}

sendPostRequest();
  • headers: Defines the content type as application/json.
  • body: Contains the parameters as a JSON string using JSON.stringify().

3. Sending Form Data

For sending form data (e.g., file uploads, form submissions):


Example: Sending Form Data in a POST Request

javascript
CopyEdit
async function sendFormData() {
    let formData = new FormData();
    formData.append("username", "john_doe");
    formData.append("file", document.querySelector("#fileInput").files[0]);

    let response = await fetch("https://example.com/upload", {
        method: "POST",
        body: formData,
    });

    let result = await response.json();
    console.log(result);
}
  • FormData handles key-value pairs, including file uploads.
  • No need to set Content-Type manually; the browser sets it automatically.

4. Sending URL-Encoded Data

For sending data like traditional HTML forms (application/x-www-form-urlencoded):


Example: Sending URL-Encoded Data

javascript
CopyEdit
async function sendURLEncodedData() {
    let params = new URLSearchParams();
    params.append("username", "john_doe");
    params.append("password", "securepassword");

    let response = await fetch("https://example.com/login", {
        method: "POST",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
        },
        body: params,
    });

    let data = await response.json();
    console.log(data);
}

sendURLEncodedData();
  • URLSearchParams formats the data properly for form submissions.




3. XMLHttpRequest vs Fetch API


Example of XMLHttpRequest:

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts', true);
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(JSON.parse(xhr.responseText));
    }
};
xhr.send();

Compared to the Fetch API, XMLHttpRequest is more verbose and harder to work with.


4. async/await with Fetch API

Using async/await makes the code cleaner and easier to read compared to chaining .then().


Example:

async function fetchPosts() {
    try {
        let response = await fetch('https://jsonplaceholder.typicode.com/posts');
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.error('Error:', error);
    }
}

fetchPosts();

Benefits of async/await:

  • Cleaner syntax.
  • Easier to debug and maintain.
  • Error handling using try...catch.

5. Error Handling in API Requests

Proper error handling ensures that your application does not break due to network failures or incorrect API responses.


Common Error Scenarios:

  1. Network Errors – When the user is offline or the server is down.
  2. Invalid JSON Response – When the server returns an unexpected format.
  3. API Errors – HTTP status codes like 404 (Not Found) or 500 (Server Error).

Best Practices for Handling Errors:

async function fetchData() {
    try {
        let response = await fetch('https://jsonplaceholder.typicode.com/comments');
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.error('Error fetching data:', error);
    }
}

fetchData();

Key Takeaways:

  • Check response.ok before processing data.
  • Use try...catch for handling errors in async/await.
  • Log detailed errors to help with debugging.

Conclusion

The Fetch API is a modern and efficient way to handle HTTP requests in JavaScript. It simplifies fetching data, handling JSON, and working with asynchronous code using async/await. By implementing proper error handling, developers can ensure their applications are robust and user-friendly.

By mastering Fetch API, you can efficiently interact with APIs and build dynamic, data-driven applications. Happy coding!


Leave a Comment


Choose Colour