API REST Có Nên Triển Khai Liên Kết Siêu Phương Tiện HATEOAS Không?

Ashley Innocent

Ashley Innocent

13 tháng 3 2026

API REST Có Nên Triển Khai Liên Kết Siêu Phương Tiện HATEOAS Không?

Apidog cho doanh nghiệp

Triển khai tại chỗ

SSO & RBAC

Tuân thủ SOC 2

Khám phá Apidog Enterprise

Các API REST có nên triển khai Liên kết siêu phương tiện HATEOAS không?

TL;DR

HATEOAS (Hypermedia as the Engine of Application State) về mặt lý thuyết rất thanh lịch nhưng thực tế lại phức tạp. Hầu hết các API bỏ qua HATEOAS hoàn toàn và chỉ sử dụng các liên kết siêu phương tiện chọn lọc cho phân trang, tài nguyên liên quan và các hành động. PetstoreAPI hiện đại triển khai các liên kết siêu phương tiện thực tế mà không bắt buộc máy khách phải hoàn toàn dựa vào siêu phương tiện.

Giới thiệu

Bạn đang đọc về thiết kế API REST. Bạn bắt gặp HATEOAS (Hypermedia as the Engine of Application State). Giải thích nói rằng: “Các máy khách nên khám phá tất cả các hành động thông qua các liên kết siêu phương tiện, chứ không phải mã hóa cứng các URL.”

Bạn nghĩ: “Nghe có vẻ phức tạp. Có ai thực sự làm điều này không?”

Câu trả lời: không hẳn. HATEOAS là ràng buộc REST bị bỏ qua nhiều nhất. Roy Fielding (người phát minh ra REST) nói rằng nó là yếu tố thiết yếu. Hầu hết các nhà thiết kế API nói rằng nó không thực tế. Kết quả: hầu hết các API “REST” không thực sự là RESTful theo định nghĩa của Fielding.

Modern PetstoreAPI áp dụng một cách tiếp cận thực dụng: sử dụng các liên kết siêu phương tiện ở những nơi chúng mang lại giá trị (phân trang, tài nguyên liên quan, hành động) nhưng không bắt buộc các máy khách phải hoàn toàn dựa vào siêu phương tiện.

💡
Nếu bạn đang xây dựng hoặc kiểm thử API REST, Apidog giúp bạn kiểm thử các liên kết siêu phương tiện, xác thực định dạng liên kết và đảm bảo API của bạn cung cấp điều hướng hữu ích. Bạn có thể xác minh tính đúng đắn của liên kết và kiểm thử các quy trình làm việc dựa trên siêu phương tiện.
nút

Trong hướng dẫn này, bạn sẽ tìm hiểu HATEOAS là gì, tại sao nó gây tranh cãi và cách triển khai các liên kết siêu phương tiện thực tế bằng cách sử dụng Modern PetstoreAPI làm tham chiếu.

HATEOAS là gì?

HATEOAS là một ràng buộc của REST nói rằng máy khách nên khám phá các khả năng của API thông qua các liên kết siêu phương tiện, chứ không phải qua tài liệu.

Khái niệm

Thay vì mã hóa cứng các URL:

// Máy khách mã hóa cứng URL
const response = await fetch('https://petstoreapi.com/v1/pets/123');
const pet = await response.json();

// Máy khách biết cấu trúc URL
await fetch(`https://petstoreapi.com/v1/pets/${pet.id}/orders`);

Máy khách theo dõi các liên kết từ phản hồi:

// Máy khách bắt đầu từ gốc
const root = await fetch('https://petstoreapi.com/v1');
const rootData = await root.json();

// Máy khách theo dõi liên kết đến thú cưng
const petsUrl = rootData._links.pets.href;
const pets = await fetch(petsUrl);
const petsData = await pets.json();

// Máy khách theo dõi liên kết đến thú cưng cụ thể
const petUrl = petsData._links.self.href;
const pet = await fetch(petUrl);
const petData = await pet.json();

// Máy khách theo dõi liên kết đến các đơn hàng
const ordersUrl = petData._links.orders.href;
const orders = await fetch(ordersUrl);

Lý thuyết

Với HATEOAS:

1. Máy khách không mã hóa cứng URL

Các URL có thể thay đổi mà không làm hỏng máy khách. Máy chủ kiểm soát cấu trúc URL.

2. Máy khách khám phá các khả năng

Nếu một liên kết tồn tại, hành động đó có sẵn. Nếu không, nó không có sẵn (hoặc không được phép cho người dùng này).

3. API tự tài liệu hóa

Máy khách khám phá API bằng cách theo dõi các liên kết, giống như duyệt một trang web.

Ví dụ: Phản hồi HATEOAS đầy đủ

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "name": "Fluffy",
  "species": "CAT",
  "status": "AVAILABLE",
  "_links": {
    "self": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24"
    },
    "update": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24",
      "method": "PUT"
    },
    "delete": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24",
      "method": "DELETE"
    },
    "orders": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/orders"
    },
    "adopt": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/adopt",
      "method": "POST"
    }
  }
}

Máy khách không cần biết các mẫu URL. Nó chỉ cần theo dõi các liên kết.

Cuộc tranh luận về HATEOAS

HATEOAS gây tranh cãi vì lý thuyết và thực tiễn khác nhau.

Các luận điểm ủng hộ HATEOAS

1. Khớp nối lỏng lẻo

Máy khách không phụ thuộc vào cấu trúc URL. Máy chủ có thể thay đổi URL mà không làm hỏng máy khách.

2. Khả năng khám phá

Máy khách có thể khám phá API mà không cần đọc tài liệu.

3. Các hành động dựa trên trạng thái

Các liên kết cho thấy những hành động nào có sẵn. Nếu một thú cưng được nhận nuôi, liên kết “nhận nuôi” sẽ biến mất.

4. REST thực sự

Roy Fielding nói HATEOAS là yếu tố thiết yếu của REST. Nếu không có nó, bạn không thực hiện REST.

Các luận điểm phản đối HATEOAS

1. Sự phức tạp

Máy khách cần logic phân tích cú pháp siêu phương tiện. Các máy khách HTTP đơn giản trở thành các máy trạng thái phức tạp.

2. Hiệu suất

Máy khách thực hiện nhiều yêu cầu để khám phá URL. Truy cập trực tiếp URL nhanh hơn.

3. Khó khăn trong việc gỡ lỗi

Theo dõi các liên kết làm cho việc gỡ lỗi khó khăn hơn. Bạn không thể chỉ curl một URL—bạn cần theo dõi chuỗi liên kết.

4. Công cụ kém

Hầu hết các máy khách HTTP, công cụ kiểm thử và trình tạo tài liệu đều giả định các URL được mã hóa cứng.

5. Không ai làm điều đó

GitHub, Stripe, Twilio, Twitter—các API lớn không sử dụng HATEOAS đầy đủ. Nếu họ không cần, bạn có cần không?

Thực tế

Hầu hết các API tự nhận là “REST” nhưng lại bỏ qua HATEOAS. Chúng thực chất là “API HTTP” hoặc “API giống REST.” REST thực sự (với HATEOAS) rất hiếm.

Các liên kết siêu phương tiện thực tế

Thay vì HATEOAS đầy đủ, hãy sử dụng các liên kết siêu phương tiện ở những nơi chúng mang lại giá trị.

1. Liên kết phân trang

Vấn đề: Máy khách cần xây dựng các URL phân trang.

Giải pháp: Cung cấp các liên kết tiếp theo/trước đó.

{
  "data": [...],
  "pagination": {
    "page": 2,
    "limit": 20,
    "totalPages": 10
  },
  "links": {
    "self": "https://petstoreapi.com/v1/pets?page=2&limit=20",
    "first": "https://petstoreapi.com/v1/pets?page=1&limit=20",
    "prev": "https://petstoreapi.com/v1/pets?page=1&limit=20",
    "next": "https://petstoreapi.com/v1/pets?page=3&limit=20",
    "last": "https://petstoreapi.com/v1/pets?page=10&limit=20"
  }
}

Lợi ích: Máy khách không cần xây dựng các URL phân trang. Chúng chỉ cần theo dõi các liên kết.

2. Liên kết tài nguyên liên quan

Vấn đề: Máy khách cần biết các mẫu URL cho các tài nguyên liên quan.

Giải pháp: Cung cấp các liên kết đến các tài nguyên liên quan.

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "name": "Fluffy",
  "_links": {
    "self": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24",
    "orders": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/orders",
    "owner": "https://petstoreapi.com/v1/users/019b4127-54d5-76d9-b626-0d4c7bfce5b6"
  }
}

Lợi ích: Máy khách khám phá các tài nguyên liên quan mà không cần tài liệu.

3. Liên kết hành động

Vấn đề: Máy khách cần biết những hành động nào có sẵn.

Giải pháp: Cung cấp các liên kết cho các hành động có sẵn.

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "status": "AVAILABLE",
  "_links": {
    "adopt": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/adopt",
      "method": "POST"
    }
  }
}

Nếu thú cưng đã được nhận nuôi:

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "status": "ADOPTED",
  "_links": {
    // Không có liên kết "nhận nuôi" - hành động không có sẵn
  }
}

Lợi ích: Các liên kết cho biết các hành động có sẵn dựa trên trạng thái.

4. Phân trang dựa trên con trỏ

Vấn đề: Máy khách cần xây dựng các URL con trỏ.

Giải pháp: Cung cấp các URL tiếp theo/trước đó mờ.

{
  "data": [...],
  "links": {
    "next": "https://petstoreapi.com/v1/pets?cursor=eyJpZCI6IjAxOWI0MTMyIn0"
  }
}

Lợi ích: Máy khách không phân tích cú pháp con trỏ. Chúng chỉ cần theo dõi các liên kết.

Cách Modern PetstoreAPI sử dụng siêu phương tiện

Modern PetstoreAPI sử dụng các liên kết siêu phương tiện chọn lọc.

Liên kết phân trang

Tất cả các điểm cuối bộ sưu tập đều bao gồm các liên kết phân trang:

GET /v1/pets?limit=20

{
  "data": [...],
  "pagination": {
    "limit": 20,
    "hasMore": true
  },
  "links": {
    "self": "https://petstoreapi.com/v1/pets?limit=20",
    "next": "https://petstoreapi.com/v1/pets?cursor=eyJpZCI6IjAxOWI0MTMyIn0&limit=20"
  }
}

Liên kết tài nguyên liên quan

Phản hồi tài nguyên bao gồm các liên kết đến các tài nguyên liên quan:

GET /v1/pets/019b4132-70aa-764f-b315-e2803d882a24

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "name": "Fluffy",
  "ownerId": "019b4127-54d5-76d9-b626-0d4c7bfce5b6",
  "_links": {
    "self": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24",
    "owner": "https://petstoreapi.com/v1/users/019b4127-54d5-76d9-b626-0d4c7bfce5b6",
    "orders": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/orders"
  }
}

Không HATEOAS đầy đủ

Modern PetstoreAPI không yêu cầu máy khách phải dựa vào siêu phương tiện. Máy khách có thể:

Tùy chọn 1: Theo dõi các liên kết (dựa trên siêu phương tiện)

const pet = await fetch(petUrl);
const ownerUrl = pet._links.owner.href;
const owner = await fetch(ownerUrl);

Tùy chọn 2: Xây dựng URL (truyền thống)

const pet = await fetch(`https://petstoreapi.com/v1/pets/${petId}`);
const owner = await fetch(`https://petstoreapi.com/v1/users/${pet.ownerId}`);

Cả hai cách tiếp cận đều hoạt động. Các liên kết được cung cấp để tiện lợi, không phải để bắt buộc.

Kiểm thử API siêu phương tiện với Apidog

Apidog giúp bạn kiểm thử các liên kết siêu phương tiện và xác thực tính đúng đắn của liên kết.

Kiểm thử sự hiện diện của liên kết

Xác minh rằng các phản hồi bao gồm các liên kết mong đợi:

// Script kiểm thử Apidog
pm.test("Response includes pagination links", () => {
  const links = pm.response.json().links;
  pm.expect(links).to.have.property('self');
  pm.expect(links).to.have.property('next');
});

Kiểm thử tính hợp lệ của liên kết

Theo dõi các liên kết và xác minh chúng hoạt động:

// Script kiểm thử Apidog
const nextUrl = pm.response.json().links.next;

pm.sendRequest(nextUrl, (err, response) => {
  pm.test("Next link returns 200", () => {
    pm.expect(response.code).to.equal(200);
  });
});

Kiểm thử định dạng liên kết

Xác minh các liên kết tuân theo định dạng mong đợi:

pm.test("Links are absolute URLs", () => {
  const links = pm.response.json().links;
  Object.values(links).forEach(link => {
    pm.expect(link).to.match(/^https:\/\//);
  });
});

Khi nào nên sử dụng HATEOAS

Sử dụng các liên kết siêu phương tiện khi chúng mang lại giá trị. Bỏ qua chúng khi không cần thiết.

Sử dụng các liên kết siêu phương tiện cho:

1. Phân trang - Máy khách không nên xây dựng các URL phân trang

2. Tài nguyên liên quan - Điều hướng tiện lợi

3. Các hành động phụ thuộc vào trạng thái - Hiển thị các hành động có sẵn dựa trên trạng thái tài nguyên

4. Quy trình làm việc phức tạp - Hướng dẫn máy khách qua các quy trình nhiều bước

Bỏ qua HATEOAS cho:

1. API CRUD đơn giản - Máy khách có thể xây dựng URL dễ dàng

2. API nội bộ - Các nhóm có thể phối hợp thay đổi URL

3. API quan trọng về hiệu suất - Các liên kết bổ sung làm tăng kích thước phản hồi

4. API di động - Băng thông quan trọng, các liên kết làm tăng chi phí phụ trội

Kết luận

HATEOAS về mặt lý thuyết rất thanh lịch nhưng thực tế lại phức tạp. Hầu hết các API bỏ qua HATEOAS đầy đủ và sử dụng các liên kết siêu phương tiện chọn lọc ở những nơi chúng mang lại giá trị.

Modern PetstoreAPI thể hiện siêu phương tiện thực tế: liên kết phân trang, liên kết tài nguyên liên quan và liên kết hành động—mà không bắt buộc máy khách phải hoàn toàn dựa vào siêu phương tiện.

Sử dụng Apidog để kiểm thử các liên kết siêu phương tiện, xác thực tính đúng đắn của liên kết và đảm bảo API của bạn cung cấp điều hướng hữu ích.

Những điểm chính:

Khám phá tài liệu Modern PetstoreAPI để xem triển khai siêu phương tiện thực tế.

nút

Câu hỏi thường gặp

HATEOAS có bắt buộc đối với API REST không?

Theo Roy Fielding (người phát minh ra REST), có. Trong thực tế, không. Hầu hết các API “REST” bỏ qua HATEOAS và về mặt kỹ thuật là “API HTTP” hoặc “API giống REST.”

HATEOAS là viết tắt của từ gì?

Hypermedia as the Engine of Application State. Nó có nghĩa là máy khách khám phá các khả năng của API thông qua các liên kết siêu phương tiện, chứ không phải các URL được mã hóa cứng.

Các API lớn có sử dụng HATEOAS không?

Không. GitHub, Stripe, Twilio và hầu hết các API lớn không sử dụng HATEOAS đầy đủ. Chúng có thể bao gồm một số liên kết siêu phương tiện (phân trang, tài nguyên liên quan) nhưng không yêu cầu máy khách phải dựa trên siêu phương tiện.

Sự khác biệt giữa HATEOAS và các liên kết siêu phương tiện là gì?

HATEOAS là một ràng buộc yêu cầu máy khách phải hoàn toàn dựa trên siêu phương tiện. Liên kết siêu phương tiện chỉ là các liên kết trong phản hồi. Bạn có thể bao gồm các liên kết mà không bắt buộc HATEOAS.

Tôi có nên triển khai HATEOAS trong API của mình không?

Có lẽ không phải HATEOAS đầy đủ. Hãy sử dụng các liên kết siêu phương tiện chọn lọc cho phân trang và các tài nguyên liên quan. Đừng bắt buộc máy khách phải dựa trên siêu phương tiện trừ khi bạn có lý do cụ thể.

Làm cách nào để kiểm thử API HATEOAS?

Sử dụng Apidog để xác minh sự hiện diện của liên kết, theo dõi các liên kết và xác thực tính đúng đắn của liên kết. Kiểm thử xem các liên kết có trả về phản hồi mong đợi không.

Định dạng HAL là gì?

HAL (Hypertext Application Language) là một định dạng tiêu chuẩn cho các liên kết siêu phương tiện. Nó sử dụng các trường `_links` và `_embedded`. Modern PetstoreAPI sử dụng định dạng liên kết lấy cảm hứng từ HAL.

Máy khách có thể bỏ qua các liên kết siêu phương tiện không?

Có. Nếu API của bạn cung cấp các liên kết nhưng không yêu cầu máy khách sử dụng chúng, máy khách có thể xây dựng URL trực tiếp. Đây là cách tiếp cận thực dụng mà hầu hết các API áp dụng.

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API