Fetch API Toàn tập: Hướng dẫn & Ví dụ JavaScript từ A-Z

Trong lập trình web hiện đại, việc giao tiếp với máy chủ là tác vụ không thể thiếu. Fetch API chính là công cụ mạnh mẽ, linh hoạt và được tích hợp sẵn trong trình duyệt để giúp bạn thực hiện điều đó một cách dễ dàng. Hãy cùng WiWeb tìm hiểu toàn bộ về Fetch API qua các hướng dẫn và ví dụ JavaScript chi tiết, giúp bạn từ bỏ phương thức XMLHttpRequest cũ kỹ và bắt đầu viết code hiệu quả hơn ngay hôm nay.

Fetch API là gì?

Nếu bạn đang làm việc với JavaScript, chắc hẳn bạn đã từng cần lấy dữ liệu từ một máy chủ nào đó. Trước đây, XMLHttpRequest (XHR) là công cụ chính để thực hiện việc này. Tuy nhiên, cú pháp của nó khá rườm rà và dựa trên callback, dễ dẫn đến tình trạng khó quản lý được gọi là “callback hell”.

Giới thiệu Fetch API: Giao diện thay thế XMLHttpRequest (XHR)

Fetch API là một giao diện JavaScript hiện đại, cho phép bạn thực hiện các yêu cầu HTTP một cách đơn giản và mạnh mẽ hơn rất nhiều. Nó được xây dựng dựa trên Promises, một khái niệm cốt lõi trong JavaScript bất đồng bộ, giúp mã của bạn trở nên sạch sẽ, dễ đọc và dễ bảo trì hơn.

Mục đích sử dụng chính của Fetch API là gì?

Mục đích chính của Fetch là để gửi yêu cầu mạng và nhận về các tài nguyên. Các tác vụ phổ biến bao gồm:

  • Lấy dữ liệu (GET) từ các điểm cuối API (API endpoints).
  • Gửi dữ liệu mới (POST) lên máy chủ, ví dụ như gửi thông tin từ một biểu mẫu.
  • Cập nhật dữ liệu đã có (PUT hoặc PATCH).
  • Xóa dữ liệu (DELETE) trên máy chủ.

Những ưu điểm vượt trội so với phương pháp cũ

So với XHR, Fetch API mang lại nhiều lợi ích rõ rệt:

  • Cú pháp đơn giản hơn: Một yêu cầu GET cơ bản chỉ cần một dòng mã.
  • Dựa trên Promises: Giúp bạn thoát khỏi các callback lồng nhau, cho phép sử dụng chuỗi .then() hoặc cú pháp async/await thanh lịch.
  • Linh hoạt hơn: API của Fetch được thiết kế tốt hơn, giúp việc xử lý các headers và các thông tin khác của yêu cầu trở nên trực quan.
  • Tích hợp sẵn: Fetch là một phần của API trình duyệt, bạn không cần cài đặt thêm bất kỳ thư viện nào để sử dụng fetch.
Fetch API là gì? Tại sao lại là lựa chọn hiện đại?
Fetch API là gì? Tại sao lại là lựa chọn hiện đại?

Hướng dẫn thực hiện yêu cầu GET cơ bản với Fetch (Ví dụ cụ thể)

Bây giờ, hãy cùng đi vào phần thực hành. Lấy dữ liệu từ một API là một trong những tác vụ phổ biến nhất, và với Fetch, việc này trở nên vô cùng đơn giản.

Cú pháp fetch() đơn giản để lấy dữ liệu

Để gửi một yêu cầu GET, bạn chỉ cần gọi hàm fetch() và truyền vào URL của API bạn muốn lấy dữ liệu. Đây là một fetch api example cơ bản:

fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => console.log(response));

Khi chạy đoạn mã trên, bạn sẽ không thấy dữ liệu JSON quen thuộc. Thay vào đó, bạn sẽ nhận được một đối tượng Response. Đây là một đối tượng đặc biệt chứa thông tin về phản hồi từ máy chủ, như mã trạng thái (status code), tiêu đề (headers), và phần thân (body) của dữ liệu.

Xử lý Response: Chuyển đổi dữ liệu với .json() và .text()

Để thực sự lấy được dữ liệu bên trong, bạn cần xử lý đối tượng Response. Fetch API cung cấp các phương thức tiện lợi để làm việc này:

  • .json(): Phân tích nội dung phản hồi dưới dạng JSON. Đây là phương thức bạn sẽ sử dụng thường xuyên nhất.
  • .text(): Trả về nội dung phản hồi dưới dạng văn bản thuần túy.

Quan trọng là các phương thức này cũng trả về một Promise, vì vậy chúng ta cần nối thêm một .then() nữa.

Luồng bất đồng bộ với Promises: Sử dụng .then() và .catch()

Đây là luồng hoàn chỉnh để lấy và sử dụng dữ liệu JSON, kết hợp xử lý lỗi cơ bản:

fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => {
    // Bước 1: Chuyển đổi đối tượng Response thành JSON
    return response.json(); 
  })
  .then(data => {
    // Bước 2: Dữ liệu đã sẵn sàng để sử dụng
    console.log('Tiêu đề bài viết:', data.title);
  })
  .catch(error => {
    // Bắt các lỗi liên quan đến mạng (ví dụ: mất kết nối)
    console.error('Đã có lỗi mạng xảy ra!', error);
  });

Cách tiếp cận này sử dụng chuỗi Promise (.then().then().catch()) rất rõ ràng. .then() đầu tiên xử lý phản hồi ban đầu, .then() thứ hai xử lý dữ liệu thực tế, và .catch() sẽ được kích hoạt nếu có lỗi mạng xảy ra trong quá trình yêu cầu.

Hướng dẫn thực hiện yêu cầu GET cơ bản với Fetch (Ví dụ cụ thể)
Hướng dẫn thực hiện yêu cầu GET cơ bản với Fetch (Ví dụ cụ thể)

Viết code sạch hơn với Async/Await và Fetch API

Mặc dù chuỗi Promise với .then() rất mạnh mẽ, cú pháp async/await được giới thiệu trong ES2017 còn giúp mã nguồn của bạn trở nên gọn gàng và dễ đọc hơn nữa. Nó cho phép bạn viết mã bất đồng bộ trông giống như mã đồng bộ.

Cú pháp async/await: Cách tiếp cận trực quan hơn

Để sử dụng cú pháp này, bạn cần khai báo hàm của mình với từ khóa async. Bên trong hàm đó, bạn có thể sử dụng từ khóa await trước lời gọi fetch() và các phương thức xử lý response. await sẽ tạm dừng việc thực thi hàm cho đến khi Promise được giải quyết.

Đây là ví dụ GET ở phần trước được viết lại bằng fetch async await:

// Khai báo hàm với từ khóa 'async'
const getPost = async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
  const data = await response.json();
  console.log('Dữ liệu từ async/await:', data);
};

getPost();

Bạn có thấy code trông tuần tự và dễ theo dõi hơn hẳn không? Không còn các khối .then() lồng nhau nữa!

Xử lý lỗi chuyên nghiệp với khối lệnh try…catch

Với async/await, cách xử lý lỗi tiêu chuẩn là sử dụng khối lệnh try...catch. Toàn bộ logic bất đồng bộ của bạn sẽ được đặt trong khối try. Nếu bất kỳ await nào trong đó thất bại (Promise bị reject), luồng thực thi sẽ nhảy ngay vào khối catch.

Đây là cách triển khai fetch api error handling một cách chuyên nghiệp:

const getPostWithHandling = async () => {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    // Bất kỳ lỗi mạng nào cũng sẽ được bắt ở đây
    console.error('Không thể lấy dữ liệu:', error);
  }
};

getPostWithHandling();

Sự kết hợp giữa async/awaittry...catch là tiêu chuẩn vàng trong lập trình javascript fetch api hiện đại vì tính rõ ràng và khả năng quản lý lỗi tuyệt vời của nó.

Viết code sạch hơn với Async/Await và Fetch API
Viết code sạch hơn với Async/Await và Fetch API

Tạo yêu cầu phức tạp: Gửi dữ liệu với POST, PUT, DELETE

Không chỉ lấy dữ liệu, Fetch API còn rất mạnh mẽ trong việc gửi, cập nhật và xóa dữ liệu. Để làm điều này, bạn cần truyền một đối tượng cấu hình (options) làm tham số thứ hai cho hàm fetch().

Cấu hình yêu cầu với đối tượng options (method, headers, body)

Đối tượng options này cho phép bạn tùy chỉnh yêu cầu của mình. Ba thuộc tính quan trọng nhất là:

  • method: Phương thức HTTP bạn muốn sử dụng (ví dụ: 'POST', 'PUT', 'DELETE'). Mặc định là 'GET'.
  • headers: Một đối tượng chứa các thông tin tiêu đề của yêu cầu. Một header phổ biến là 'Content-Type': 'application/json' để báo cho máy chủ biết bạn đang gửi dữ liệu dạng JSON.
  • body: Dữ liệu bạn muốn gửi đi. Khi gửi JSON, bạn cần chuyển đổi đối tượng JavaScript của mình thành một chuỗi JSON bằng JSON.stringify().

Ví dụ thực tế: Gửi dữ liệu JSON bằng phương thức POST

Hãy xem một javascript fetch post request example hoàn chỉnh. Giả sử chúng ta muốn tạo một bài viết mới:

const createPost = async () => {
  const newPost = {
    title: 'Bài viết mới của WiWeb',
    body: 'Đây là nội dung bài viết.',
    userId: 1,
  };

  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
      method: 'POST', // Chỉ định phương thức là POST
      headers: {
        'Content-Type': 'application/json', // Báo cho server biết ta gửi JSON
      },
      body: JSON.stringify(newPost), // Chuyển đổi object thành chuỗi JSON
    });

    const data = await response.json();
    console.log('Server trả về:', data);
  } catch (error) {
    console.error('Lỗi khi gửi dữ liệu:', error);
  }
};

createPost();

Đoạn mã này là một ví dụ điển hình cho fetch api post. Nó định nghĩa dữ liệu, cấu hình yêu cầu, gửi đi và xử lý phản hồi từ máy chủ.

Cách cập nhật và xóa dữ liệu (PUT & DELETE)

Việc cập nhật (PUT) và xóa (DELETE) dữ liệu cũng tuân theo cấu trúc tương tự. Bạn chỉ cần thay đổi giá trị của thuộc tính method và URL (thường bao gồm ID của tài nguyên cần tác động).

  • Ví dụ với PUT (Cập nhật):
    javascript
    // ... bên trong một hàm async
    fetch('https://jsonplaceholder.typicode.com/posts/1', {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ title: 'Tiêu đề đã được cập nhật' })
    });
  • Ví dụ với DELETE (Xóa):
    javascript
    // ... bên trong một hàm async
    fetch('https://jsonplaceholder.typicode.com/posts/1', {
    method: 'DELETE',
    });

Yêu cầu DELETE thường không cần headers hay body.

Tạo yêu cầu phức tạp: Gửi dữ liệu với POST, PUT, DELETE
Tạo yêu cầu phức tạp: Gửi dữ liệu với POST, PUT, DELETE

Xử lý lỗi (Error Handling) trong Fetch API

Một trong những điểm cần lưu ý nhất khi làm việc với Fetch API là cách nó xử lý các lỗi HTTP. Đây là điểm khác biệt lớn so với các thư viện như Axios và có thể gây nhầm lẫn cho người mới bắt đầu.

Tại sao .catch() không bắt được lỗi HTTP (404, 500)?

Khối .catch() (hoặc try...catch với async/await) của một Promise fetch() chỉ được kích hoạt khi có lỗi mạng thực sự xảy ra. Ví dụ như không có kết nối internet, lỗi DNS, hoặc máy chủ không thể truy cập.

Tuy nhiên, nếu máy chủ phản hồi thành công với một mã trạng thái lỗi HTTP như 404 (Not Found) hoặc 500 (Internal Server Error), fetch() vẫn coi đây là một yêu cầu thành công. Promise sẽ không bị reject. Điều này có nghĩa là code trong .catch() sẽ không chạy.

Kiểm tra thuộc tính response.ok và response.status để xử lý lỗi

Giải pháp đúng đắn là bạn phải tự mình kiểm tra trạng thái của phản hồi. Đối tượng Response cung cấp hai thuộc tính hữu ích cho việc này:

  • response.ok: Một thuộc tính boolean. Nó sẽ là true nếu mã trạng thái nằm trong khoảng 200-299, và false nếu nằm ngoài khoảng đó.
  • response.status: Chứa mã trạng thái HTTP thực tế (ví dụ: 200, 404, 503).

Đây là cách xử lý lỗi HTTP chuẩn với Fetch API:

const fetchUserData = async () => {
  try {
    const response = await fetch('https://api.example.com/user/non-existent-user');

    // Kiểm tra xem yêu cầu có thành công không
    if (!response.ok) {
      // Nếu không, tạo một lỗi mới để khối catch có thể bắt được
      throw new Error(`Lỗi HTTP! Trạng thái: ${response.status}`);
    }

    const data = await response.json();
    console.log(data);
  } catch (error) {
    // Khối catch này giờ có thể bắt cả lỗi mạng và lỗi HTTP
    console.error('Không thể lấy dữ liệu người dùng:', error.message);
  }
};

Xử lý các lỗi mạng và sự cố kết nối

Như đã đề cập, các lỗi mạng thực sự (mất kết nối, sai tên miền…) sẽ tự động bị try...catch hoặc .catch() bắt được. Bằng cách kết hợp kiểm tra response.ok và khối catch, bạn đã có một hệ thống fetch api error handling toàn diện, xử lý được cả hai trường hợp.

Xử lý lỗi (Error Handling) trong Fetch API
Xử lý lỗi (Error Handling) trong Fetch API

Các câu hỏi thường gặp về Fetch API (FAQ)

Khi làm việc với Fetch API, có một vài câu hỏi mà các lập trình viên thường xuyên đặt ra. WiWeb đã tổng hợp và giải đáp những thắc mắc phổ biến nhất ở đây.

Cả Fetch và Axios đều dùng để thực hiện yêu cầu HTTP, nhưng có những khác biệt quan trọng:

  • Tích hợp: Fetch được tích hợp sẵn trong trình duyệt. Axios là một thư viện của bên thứ ba, bạn phải cài đặt nó.
  • Xử lý JSON: Fetch yêu cầu bạn thực hiện hai bước (lấy response, sau đó gọi .json()). Axios tự động chuyển đổi dữ liệu JSON.
  • Xử lý lỗi: Fetch không coi lỗi HTTP (404, 500) là lỗi và không reject Promise. Axios sẽ reject Promise khi gặp các lỗi này, giúp việc bắt lỗi trong khối .catch() đơn giản hơn.
  • Hủy yêu cầu: Cả hai đều hỗ trợ hủy yêu cầu, nhưng cú pháp khác nhau. Fetch dùng AbortController.

Khi nào nên dùng?

  • Dùng Fetch API: Khi bạn muốn một giải pháp nhẹ, không cần thêm thư viện, cho các dự án đơn giản hoặc khi bạn muốn kiểm soát hoàn toàn quá trình xử lý.
  • Dùng Axios: Khi dự án của bạn lớn, cần các tính năng nâng cao như interceptors (chặn và sửa đổi yêu cầu/phản hồi), xử lý lỗi đơn giản hơn, hoặc cần hỗ trợ các trình duyệt cũ.

Trong React, bạn thường gọi API bên trong hook useEffect để tránh các tác dụng phụ không mong muốn. Dữ liệu trả về sẽ được lưu trong state bằng hook useState.

import React, { useState, useEffect } from 'react';

function UserProfile() {
  const [user, setUser] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchUser = async () => {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
        if (!response.ok) {
          throw new Error('Lỗi khi lấy dữ liệu');
        }
        const data = await response.json();
        setUser(data);
      } catch (err) {
        setError(err.message);
      }
    };

    fetchUser();
  }, []); // Mảng rỗng đảm bảo useEffect chỉ chạy một lần

  if (error) return <div>Lỗi: {error}</div>;
  if (!user) return <div>Đang tải...</div>;

  return <h1>{user.name}</h1>;
}

Đôi khi, bạn muốn hủy một yêu cầu đang diễn ra, ví dụ như khi người dùng điều hướng sang trang khác. AbortController là API tiêu chuẩn để làm việc này.

  1. Tạo một instance của AbortController.
  2. Truyền controller.signal vào đối tượng options của fetch.
  3. Gọi controller.abort() khi bạn muốn hủy yêu cầu.
const controller = new AbortController();
const signal = controller.signal;

fetch('https://api.example.com/data', { signal })
  .then(response => response.json())
  .catch(err => {
    if (err.name === 'AbortError') {
      console.log('Yêu cầu đã được hủy!');
    }
  });

// Hủy yêu cầu sau một khoảng thời gian
setTimeout(() => controller.abort(), 1000);
Các câu hỏi thường gặp về Fetch API (FAQ)
Các câu hỏi thường gặp về Fetch API (FAQ)

Lời kết

Qua bài viết này, chúng ta đã cùng nhau tìm hiểu sâu về Fetch API, từ những yêu cầu GET đơn giản nhất đến việc gửi dữ liệu phức tạp và xử lý lỗi một cách chuyên nghiệp. Với cú pháp hiện đại dựa trên Promise và async/await, Fetch API thực sự là một công cụ không thể thiếu cho bất kỳ nhà phát triển web nào.

Nó giúp mã nguồn của bạn trở nên gọn gàng, dễ đọc và mạnh mẽ hơn. Bằng cách nắm vững các khái niệm như đối tượng Response, cách kiểm tra response.ok, và sử dụng AbortController, bạn đã sẵn sàng để xây dựng các ứng dụng web tương tác hiệu quả.

Bạn có mẹo hay nào khác khi sử dụng Fetch API không? Hãy chia sẻ với WiWeb trong phần bình luận bên dưới nhé!

Nếu bạn đang tìm kiếm một đơn vị thiết kế website chuyên nghiệp để áp dụng những kỹ thuật hiện đại này, đừng ngần ngại liên hệ với WiWeb. Chúng tôi luôn sẵn sàng đồng hành cùng bạn.

5/5 - (83 Đánh giá)
Bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *