You are on page 1of 100

Machine Translated by Google

bất kỳ tài liệu XML nào. Nhưng tôi nghi ngờ đó không phải là điều bạn đang nghĩ tới. Bạn có thể muốn thứ gì

đó cụ thể hơn một chút: HTML, HAL, Siren hoặc AtomPub.

Nếu bạn muốn cung cấp các biểu diễn JSON và XML có cùng ngữ nghĩa, bạn nên chọn một tiêu chuẩn hypermedia

cung cấp cả hai “hương vị”. Hiện tại điều đó có nghĩa là HAL hoặc OData, mặc dù phiên bản XML của Siren đã

được lên kế hoạch.

Nếu API của bạn ở chế độ chỉ đọc—nghĩa là sơ đồ trạng thái của bạn không bao gồm bất kỳ chuyển đổi không an

toàn nào—bạn có rất nhiều lựa chọn tốt. Tôi đề xuất HTML, HAL hoặc JSON-LD.

Nếu API của bạn bao gồm các chuyển đổi không an toàn thì điều đó sẽ hạn chế các lựa chọn của bạn. JSON-LD

không thể tự biểu thị các chuyển đổi trạng thái không an toàn; bạn sẽ cần thêm Hydra (xem Chương 12). HAL hỗ

trợ các quá trình chuyển đổi không an toàn, nhưng theo một cách nào đó, tôi nghĩ nó hoạt động không hiệu quả.

Bộ sưu tập+JSON hỗ trợ ba chuyển đổi không an toàn cụ thể: thêm mục mới vào bộ sưu tập, chỉnh sửa mục và xóa

mục. Đó là nó. Bạn không thể sử dụng bất kỳ chuyển đổi không an toàn nào ngoài ba chuyển tiếp được xác định

bởi loại phương tiện.

Bước 5: Viết hồ sơ Khi máy chủ

của bạn gửi một biểu diễn, nó sẽ bao gồm tiêu đề Kiểu nội dung , cho khách hàng biết cách phân tích cú pháp

biểu diễn. Bạn cũng sẽ bao gồm một liên kết đến một hoặc nhiều cấu hình, điều này sẽ giải thích ngữ nghĩa

ứng dụng của biểu diễn.

Ở bước 3, bạn có thể sẽ tìm thấy một số cấu hình hiện có bao hàm một số ngữ nghĩa ứng dụng của mình, nhưng

có thể bạn sẽ không thể bao quát được mọi thứ. Sẽ có điều gì đó đặc biệt về API của bạn. Bạn sẽ mô tả những

điểm đặc biệt bằng cách viết một hồ sơ mới.

Đoạn mã đánh dấu này cho trò chơi mê cung của Chương 7 nhập hai cấu hình ALPS—một cấu hình từ Alps.io mang

ngữ nghĩa của Mê cung+XML và một cấu hình tùy chỉnh giải thích bổ sung duy nhất tôi đã thực hiện cho Mê

cung+XML: bí ẩn công tắc.

<link rel="profile" href="http://alps.io/example/maze"/>


<link rel="profile" href="/switches.alps"/>

Hồ sơ của bạn có thể là tài liệu ALPS, ngữ cảnh JSON-LD hoặc trang web sử dụng vi định dạng XMDP. Nếu không

có lựa chọn nào trong số này phù hợp với bạn, bạn có thể từ bỏ ý tưởng về một hồ sơ có thể đọc được bằng máy

và thay vào đó viết một hồ sơ có thể đọc được bằng con người.

Hồ sơ mà con người có thể đọc được trông giống như tài liệu API truyền thống. Đó là một trang web trình bày

ý nghĩa của tất cả các mối quan hệ liên kết và mô tả ngữ nghĩa. Bạn vẫn có thể sử dụng lại các mối quan hệ

liên kết và mô tả từ Alps.io và các hồ sơ khác—chỉ cần sao chép và dán văn bản, đồng thời đảm bảo liên kết

trở lại hồ sơ ban đầu.

Bước 6: Triển khai Bạn sẽ dành phần

lớn thời gian cho bước này và tôi không có nhiều lời khuyên vì nó phụ thuộc vào framework và ngôn ngữ lập

trình bạn đang sử dụng. nếu bạn

Quy trình thiết kế bảy bước | 169


Machine Translated by Google

có một sơ đồ trạng thái và một hồ sơ mà bạn hài lòng thì đó không hẳn là một công việc dễ dàng

nhưng ít nhất nó phải đơn giản.

Bước 7: Xuất bản Nếu bạn

may mắn và tìm thấy một tiêu chuẩn dành riêng cho miền hiện có thực hiện chính xác những gì bạn

cần mà không cần tiện ích mở rộng cần thiết thì bạn đã bỏ qua ngay đến bước 6 và giờ bạn đã hoàn

tất. Tài liệu API của bạn bao gồm một URL ("URL bảng quảng cáo" của API của bạn) và một giá trị
cho tiêu đề Kiểu nội dung .

Nhưng điều đó gần như không bao giờ xảy ra. Việc đáp ứng các yêu cầu kinh doanh của bạn chắc

chắn đòi hỏi bạn phải mở rộng tiêu chuẩn hiện có hoặc thiết kế một tiêu chuẩn hoàn toàn mới.

Tại thời điểm này trong quy trình, bạn đã thiết kế phần “mới” và mô tả nó bằng cách sử dụng một
số kết hợp giữa cấu trúc máy có thể đọc được (như cấu hình ALPS) và văn bản con người có thể

đọc được (như định nghĩa về loại phương tiện) . Việc duy nhất còn lại là công bố thông tin đó.

Điều này phức tạp hơn việc chỉ đưa một số tài liệu API lên trang web của bạn, nhưng nó cũng

không phức tạp hơn nhiều . Tôi chỉ trình bày tất cả để bạn không vô tình bỏ qua một bước.

Xuất bản URL biển quảng

cáo của bạn Quay lại bước 2, tôi đã nói rằng bạn nên có một hộp trên sơ đồ trạng thái có một

mũi tên bất ngờ xuất hiện. Hộp này đại diện cho trang chủ của bạn: một cổng siêu phương tiện

tới tất cả các tài nguyên khác của bạn. Mọi người muốn viết ứng dụng khách cho API của bạn đều

phải biết URL trang chủ của bạn. Phần còn lại có thể thương lượng.

Nếu bạn đã vượt qua bước 2 mà không thiết kế tài nguyên “trang chủ”, tôi khuyên bạn nên quay

lại bước 2 và thiết kế một tài nguyên. URL biển quảng cáo là phần thông tin quan trọng nhất về

API của bạn, vì đó là cửa ngõ dẫn đến mọi thứ khác.

Xuất bản hồ sơ của

bạn Tài liệu hồ sơ của bạn xuất hiện trên trang web của bạn, cùng với phần còn lại của thông

tin về API. Nếu bạn đã viết hồ sơ ALPS, tôi sẽ đánh giá cao nếu bạn cũng đăng ký hồ sơ đó với

Cơ quan đăng ký ALPS tại Alps.io. Điều này sẽ giúp người khác tìm và sử dụng lại các mối quan

hệ liên kết và các bộ mô tả ngữ nghĩa mà bạn đã xác định.

Đăng ký loại phương tiện

mới Có thể bạn sẽ không cần thiết kế loại phương tiện mới, vì vậy tôi sẽ không chiếm chỗ ở đây

để giải thích những việc cần làm sau khi bạn thiết kế xong. (Thay vào đó, tôi sẽ đề cập đến vấn

đề này sau, trong phần “Nếu bạn thiết kế một loại phương tiện truyền thông” ở trang 183). Đủ để

nói rằng sau khi triển khai hoạt động, bạn phải đủ tự tin vào thiết kế của mình để đăng ký loại

phương tiện mới với IANA.

170 | Chương 9: Quy trình thiết kế


Machine Translated by Google

Đăng ký các quan hệ liên kết

mới Nếu các quan hệ liên kết của bạn là URL (RFC 5988 gọi là “các loại quan hệ mở rộng”), bạn không cần

phải làm bất kỳ điều gì đặc biệt ở đây. Không ai có thể xác định mối quan hệ liên kết xung đột với mối

quan hệ của bạn, bởi vì bạn đã đặt tên cho các mối quan hệ của mình theo tên miền mà bạn kiểm soát. Nếu

bạn không nghĩ rằng bất kỳ nhà cung cấp API nào khác sẽ muốn sử dụng lại các mối quan hệ liên kết của

mình, bạn cũng có thể tránh cho mình một số rắc rối và sử dụng các mối quan hệ mở rộng.

Nhưng xuyên suốt cuốn sách này, tôi đã tránh xa các mối quan hệ liên kết mở rộng. Chúng quá dài

để sử dụng đi sử dụng lại trong bản in. Thay vào đó, tôi đã sử dụng các mối quan hệ liên kết là

các chuỗi ngắn, như west và flip. RFC 5988 gọi đây là “các loại quan hệ đã đăng ký” và để tránh

xung đột, chúng cần phải được đăng ký ở đâu đó. Nếu bạn đọc một tài liệu HTML sử dụng

rel="current", thì phải rõ ràng liệu hiện tại đề cập đến mục gần đây nhất trong bộ sưu tập hay
đến phép đo dòng điện.

RFC 5988 không nói chính xác cách đăng ký mối quan hệ liên kết, nhưng tôi muốn nói có bốn cách:

• Nó có thể được tìm thấy trong sổ đăng ký quan hệ liên kết của IANA. Bất kỳ nhà cung cấp API nào cũng được

phép sử dụng các mối quan hệ liên kết đã đăng ký IANA trong các biểu diễn của mình mà không cần xác định chúng.

Một ví dụ hữu ích là mối quan hệ trả lời được xác định trong RFC 4685.

Phần 6.2 của RFC 5988 mô tả quy trình đăng ký IANA. Việc đưa mối quan hệ liên kết vào sổ

đăng ký này yêu cầu phải viết RFC (hoặc tài liệu tương đương) và chỉ những mối quan hệ hữu

ích nói chung mới được chấp nhận, vì vậy tương đối ít nhà phát triển sẽ đi theo con đường
này.

• Mối quan hệ liên kết có thể được xác định cùng với loại phương tiện, theo cách Maze+XML xác

định hướng tây và lối ra. Một số loại phương tiện khác có thể định nghĩa mối quan hệ thoát

khác nhau, nhưng ai quan tâm? Một tài liệu chỉ có thể có một loại phương tiện nên luôn rõ

ràng những quy tắc nào cần áp dụng.

Nếu loại phương tiện xác định mối quan hệ liên kết xung đột với mối quan hệ đã đăng ký với

IANA thì định nghĩa của loại phương tiện đó sẽ được ưu tiên. Đừng cố ý làm điều này!

Tôi đang đánh vần quy tắc này để ngữ nghĩa ứng dụng API của bạn không thay đổi vì loại phương

tiện của nó sử dụng mối quan hệ liên kết mà ai đó vừa đăng ký với
IANA.

• Mối quan hệ liên kết có thể được xác định trong một cấu hình máy có thể đọc được chẳng hạn

như tài liệu ALPS. Một số hồ sơ khác có thể định nghĩa mọi thứ khác nhau, nhưng ai quan tâm?

Tài liệu này không sử dụng hồ sơ đó.

Nếu một cấu hình xác định mối quan hệ liên kết xung đột với mối quan hệ được xác định bởi

loại phương tiện hoặc mối quan hệ đã đăng ký IANA thì định nghĩa của cấu hình sẽ được ưu tiên.

Một lần nữa, đừng cố ý làm điều này. Đây là quy tắc “trong trường hợp khẩn cấp”.

Quy trình thiết kế bảy bước | 171


Machine Translated by Google

• Mối quan hệ liên kết có thể được đăng ký với Microformats wiki.1 Trang wiki không độc quyền lắm; nó cố gắng lập

danh mục mọi mối quan hệ liên kết từng thấy hoặc được đề xuất sử dụng trong HTML.

Wiki Microformats tạo ra một nền tảng thử nghiệm tốt cho các mối quan hệ liên kết mà một ngày nào đó có thể được

đưa vào sổ đăng ký IANA. Nếu bạn muốn người khác sử dụng mối quan hệ liên kết mà bạn đã phát minh ra, việc đưa

nó lên wiki này là một cách hay để kiểm tra nó. Nếu không, tôi khuyên bạn nên sử dụng mối quan hệ mở rộng thay
thế.

Với ALPS, bạn có thể chia đôi sự khác biệt. Bạn có thể sử dụng URL đầy đủ cho bất kỳ mối quan hệ liên kết nào được xác

định trong tài liệu ALPS dưới dạng mối quan hệ liên kết mở rộng (ví dụ: http://alps.io/example/ maze#exit), ngay cả

khi bạn chưa đưa tài liệu ALPS đó làm hồ sơ. Khi bạn đưa tài liệu ALPS làm hồ sơ, bạn có thể xử lý các quan hệ liên

kết của nó như các quan hệ liên kết đã đăng ký (thoát).

Xuất bản phần còn lại của tài liệu

Còn rất nhiều tài liệu nữa sẽ được xuất bản, nhưng tất cả đều là tài liệu dành riêng cho API của bạn mà con người có

thể đọc được: tóm tắt, ví dụ, mã mẫu, hướng dẫn thiết lập ủy quyền, bản sao tiếp thị giải thích API của bạn khác với

các API khác như thế nào.

Nội dung này quan trọng nhưng bạn không cần sự khuyến khích của tôi để xuất bản nó. Đây là thứ chúng tôi nghĩ đến khi

nghĩ về tài liệu API. Tôi đã hạ thấp tầm quan trọng của tài liệu mà con người có thể đọc được trong suốt quá trình

này, vì theo kinh nghiệm của tôi, nó thường được sử dụng để thay thế cho các điều khiển siêu phương tiện.

Máy khách phần mềm có khả năng hạn chế trong việc thích ứng với những thay đổi trong tài liệu hypermedia.

Phần mềm dựa trên các tài liệu con người có thể đọc được không có khả năng thích ứng. Nếu một API chỉ được mô tả bằng

văn xuôi thì việc thay đổi văn xuôi có nghĩa là viết lại tất cả các ứng dụng khách. Đó là một vấn đề lớn với các API

hiện tại và đó là vấn đề mà tôi đang cố gắng giải quyết bằng cuốn sách này.

Tôi muốn kéo dài khả năng thích ứng của khách hàng càng nhiều càng tốt. Điều này có nghĩa là một quy trình thiết kế

tập trung chặt chẽ vào việc tạo ra các tài liệu có thể đọc được bằng máy, trong đó các tài liệu mà con người có thể

đọc được chỉ nhằm mục đích mang lại sự thuận tiện cho con người.

Các URI nổi tiếng

Đây là một suy nghĩ: điều gì sẽ xảy ra nếu bạn không cần quảng cáo URL biển quảng cáo của mình? Điều gì sẽ xảy ra nếu

khách hàng của bạn biết cách tìm điểm vào API của bạn? Đó là lời hứa về “URI nổi tiếng” của IANA được thành lập vào

năm 2010 bởi RFC 5785.

Nếu máy chủ trình bày các biểu diễn ở Định dạng Liên kết CoRE (được đề cập trong Chương 13), thì không cần phải thắc

mắc URL biển quảng cáo là gì. Nó phải luôn là /.well-known/core.

URL (tương đối) đó được đăng ký với IANA. Thay vì tìm hiểu một URL biển quảng cáo khác nhau cho mỗi máy chủ, máy khách

CoRE luôn có thể gửi yêu cầu GET tới /.well-known/

1. Trang này nằm ở đây.

172 | Chương 9: Quy trình thiết kế


Machine Translated by Google

core và nhận danh sách các liên kết hypermedia đến các tài nguyên khác được lưu trữ trên máy
chủ đó. Máy chủ phân phát tài liệu siêu dữ liệu máy chủ web (Chương 12) phải luôn phân phối
tài liệu đó từ /.well-known/host-meta hoặc /well-known/host-meta.json.

Đây là một điều khá nhỏ, nhưng nó đóng lại phần cuối cùng của khoảng cách ngữ nghĩa. Nhờ Cơ
quan đăng ký URI nổi tiếng, về mặt lý thuyết, khách hàng có thể khám phá và tìm hiểu một API
mới, chỉ cần cung cấp tên máy chủ.

Điều đáng chú ý là các URI nổi tiếng thường được liên kết với các loại phương tiện cụ thể.
Khi tôi viết bài này, nếu bạn không sử dụng Định dạng liên kết CoRE hoặc siêu dữ liệu máy
chủ web, bạn không thể xuất bản API của mình tại một URI nổi tiếng. Đó là hai định dạng duy
nhất trong Sổ đăng ký URI nổi tiếng hữu ích cho API.

Ví dụ: Bạn gõ nó, chúng tôi đăng nó

Phải mất một thời gian để chạy trò chơi mê cung của Chương 7 trong suốt quá trình thiết kế của tôi,

bởi vì tôi đã giải thích từng bước của quy trình khi thực hiện. Đây là một ví dụ khác ngắn hơn

nhiều. Tôi sẽ chỉ đưa ra các quyết định của mình thay vì giải thích tất cả các bước. Miền vấn đề

của tôi sẽ là trang web “Bạn gõ nó, chúng tôi đăng nó” từ Chương 1. Tôi sẽ thực hiện năm bước đầu

tiên và kết thúc bằng một thiết kế và một hồ sơ, nhưng không thực hiện.

Liệt kê các bộ mô tả ngữ nghĩa

Nhìn vào mô tả của trang web từ Chương 1, tôi đã xác định được các mô tả ngữ nghĩa sau:

• Trang chủ

— Một số loại văn bản “về trang web này”

- Danh sách tin nhắn

- Một tin nhắn cá nhân

- ID của tin nhắn

- Nội dung tin nhắn

- Ngày xuất bản của tin nhắn

Sau đó, tôi nhóm các phần mô tả theo cách mà tôi cho là hợp lý. Kết quả là trong Hình 9-9.
Tôi có ba loại trình bày riêng biệt: văn bản “về trang web này”, danh sách thư và một thư
riêng lẻ. Tôi quyết định sử dụng danh sách tin nhắn làm “trang chủ” thay vì có một trang chủ
riêng chỉ liên kết đến danh sách tin nhắn và “về trang web này”.

Ví dụ: Bạn gõ nó, chúng tôi đăng nó | 173


Machine Translated by Google

Hình 9-9. Các bộ mô tả ngữ nghĩa cho You Type It…, được nhóm thành các biểu diễn

Vẽ sơ đồ trạng thái Hình 9-10

thể hiện sơ đồ trạng thái mà tôi đã nghĩ ra.

Hình 9-10. Sơ đồ trạng thái ban đầu cho API You Type It…

Sử dụng các liên kết trên trang web You Type It… làm hướng dẫn, tôi đã kết nối ba loại tài
nguyên với các chuyển đổi trạng thái an toàn. Tôi cũng đã tạo một quá trình chuyển đổi trạng

thái không an toàn, tương ứng với biểu mẫu HTTP POST trên trang web tạo thông báo mới.

Đối chiếu tên


Khi đặt tên cho các chuyển đổi trạng thái an toàn cho sơ đồ trạng thái, tôi đảm bảo chọn các

tên đã đăng ký IANA: about, sưu tập và mục. Văn bản “về trang web này” là một tài liệu mà con
người có thể đọc được, vì vậy tôi sẽ không lo lắng về các phần mô tả ngữ nghĩa của nó.

Còn lại sáu thứ cần đặt tên mà IANA không giúp được gì: “danh sách tin nhắn”, “tin nhắn”,
“tạo”, “ID”, “văn bản” và “ngày xuất bản”. Xem qua “Sở thú ngữ nghĩa” ở trang 230 sẽ giúp ích
cho năm vấn đề trong số đó.

Có một mục vi dữ liệu lược đồ.org có tên là BlogPosting (http://schema.org/BlogPost ing), mục

này xác định các bộ mô tả ngữ nghĩa được gọi là ArticleBody và dateCreated. Cái đó

174 | Chương 9: Quy trình thiết kế


Machine Translated by Google

quản lý “tin nhắn”, “văn bản” và “ngày xuất bản”. Một tập hợp các bài đăng trên blog của Schema.org

được gọi là Blog. Việc đó sẽ xử lý “danh sách tin nhắn”.

Tôi sẽ đặt tên cho bài chuyển tiếp trạng thái không an toàn của mình. Tôi lấy tên đó từ tiêu chuẩn

Luồng hoạt động, trong đó nó có nghĩa là “Hành động tạo một đối tượng và sau đó xuất bản nó trực tuyến”.

Không ai từng dự định các động từ vi dữ liệu lược đồ.org và Luồng hoạt động sẽ hoạt động cùng nhau,

nhưng ALPS cho phép tôi kết hợp ngữ nghĩa ứng dụng của chúng.

Điều đó để lại ID tin nhắn. Tôi quyết định tôi thực sự không cần phải cung cấp thông tin này. Mỗi tin

nhắn đã có một ID duy nhất: URL của nó. Tại sao khách hàng nên quan tâm đến ID nội bộ mà máy chủ sử

dụng? Vì vậy, tôi quyết định bỏ nó khỏi API của mình.

Hình 9-11 hiển thị sơ đồ trạng thái của tôi sau khi tôi đối chiếu các tên. Lưu ý rằng liên kết mục

hiện có hai quan hệ liên kết: item và blogPost. Mối quan hệ liên kết thứ hai xuất phát từ mục Blog

của lược đồ.org , mục này xác định blogPost là mối quan hệ giữa một Blog và một BlogPost. Điều này

hơi dư thừa với mối quan hệ mục chung chung hơn của IANA , nhưng không có lý do gì tôi không thể gắn

cả hai mối quan hệ liên kết vào một liên kết duy nhất. Bằng cách đó, những khách hàng hiểu Blog và

BlogPost của lược đồ cũng sẽ không cần hiểu mục của IANA.

Hình 9-11. Sơ đồ trạng thái cho API You Type It…, sau khi đối chiếu tên.

Tôi có đang tạo API tiểu blog thứ 58 trên thế giới không? Theo một nghĩa nào đó, đúng vậy. Nhưng tôi

không định nghĩa điều gì mới cả. Tôi đã lấy mọi thứ từ IANA, Schema.org và Luồng hoạt động. Một khách

hàng đã hiểu các bộ mô tả ngữ nghĩa và các mối quan hệ liên kết này sẽ hiểu API của tôi. Không có

nhiều khả năng một khách hàng như vậy tồn tại, nhưng có nhiều khả năng một phần của khách hàng đó tồn

tại hơn là nếu tôi thiết kế lại những khái niệm cơ bản này lần thứ 58.

Chọn loại phương tiện Tôi có

thể chọn từ rất nhiều loại phương tiện. Sơ đồ trạng thái của tôi giống như Hình 9-7, vì vậy loại

phương tiện triển khai mẫu bộ sưu tập sẽ giúp ích rất nhiều. API YouTypeItWePostIt.com thực tế, như

được trình bày trong Chương 2, sử dụng Collection+JSON. Tôi cũng có thể đi theo con đường hypermedia

thuần túy: trang web YouTypeItWePostIt.com sử dụng

Ví dụ: Bạn gõ nó, chúng tôi đăng nó | 175


Machine Translated by Google

HTML. Và tôi thậm chí có thể chọn một tiêu chuẩn dành riêng cho tên miền. Trong Chương 6, tôi

coi AtomPub như một tiêu chuẩn chung về “mẫu bộ sưu tập”, nhưng ban đầu nó được xác định cụ thể

để xuất bản các đoạn văn bản độc lập.

Sự lựa chọn của tôi có thể thay đổi từ vựng tôi sử dụng. Nếu tôi chọn Atom làm định dạng trình

bày của mình, tôi cần ngừng gọi nội dung của thông báo là ArticleBody và bắt đầu gọi nó là nội
dung, vì đó là cách Atom gọi nó.

Để đa dạng hơn, tôi sẽ chọn HAL. Biểu diễn HAL+XML của danh sách thư có thể trông như thế này:

<resource href="/">
<link rel="profile" href="http://alps.io/schema.org/Blog"/> <link
rel="profile" href="http://alps. io/schema.org/BlogPost"/> <link rel="profile"
href="http://alps.io/activitystrea.ms/verbs"/> <link rel="about" href="/about-
this -trang">

<Blog>
<link rel="post" href="/messages"/>

<resource href="/messages/2" rel="item">


<BlogPost>
<articleBody>Đây là tin nhắn số 2.</articleBody>
<dateCreated>24-04-2013</dateCreated> </
BlogPost>
</tài nguyên>

<resource href="/messages/1" rel="item">


<BlogPost>
<articleBody>Đây là tin nhắn số 1.</articleBody>
<dateCreated>2013-04-22</dateCreated> </
BlogPost> </
tài nguyên>
</Blog>
</resource>

Điều này truyền tải tất cả trạng thái tài nguyên cần thiết (mô tả về hai thông báo trong
danh sách thông báo) và bao gồm tất cả các liên kết hypermedia cần thiết (với hồ sơ quan hệ
liên kết , giới thiệu, mục và bài đăng).

Đã xảy ra sự cố với liên kết bài đăng : không rõ liệu đó có phải là quá trình chuyển đổi trạng

thái không an toàn cần được kích hoạt bằng POST hay không và không rõ khách hàng nên gửi nội

dung thực thể nào cùng với yêu cầu POST. Nhưng đó là do thiếu sót chung của HAL. Nếu tôi không

thích tính năng đó của HAL, tôi có thể chọn loại phương tiện khác vào thời điểm này.

Viết hồ sơ
Vì tôi đã lấy tất cả ngữ nghĩa ứng dụng của mình từ các hồ sơ hiện có nên về mặt kỹ thuật tôi

không cần phải viết hồ sơ của riêng mình. Biểu diễn ví dụ chỉ liên kết đến ba cấu hình ALPS
hiện có:

176 | Chương 9: Quy trình thiết kế


Machine Translated by Google

<link rel="profile" href="http://alps.io/schema.org/Blog"/> <link


rel="profile" href="http://alps.io/schema.org/BlogPost" /> <link rel="profile"
href="http://alps.io/activitystrea.ms/verbs"/>

Điều đó bao gồm mọi thứ ngoại trừ mối quan hệ liên kết IANA và mục mà tôi được phép sử dụng
mà không cần giải thích.

Đây là hồ sơ ALPS độc lập cho thiết kế “Bạn gõ nó, chúng tôi đăng nó” của tôi (nó hơi dư
thừa, nhưng đó là một tài liệu duy nhất chứa tất cả các mối quan hệ liên kết và mô tả ngữ
nghĩa mà API của tôi thực sự sử dụng):

<alps>
<descriptor id="about" type="semantic"
href="http://alps.io/iana/relations#about"/>

<descriptor id="Blog" type="semantic" href="http://alps.io/schema.org/Blog"> <descriptor


id="blogPost" type="semantic"
href="http://alps.io/schema.org/Blog#blogPost" rt="#BlogPosting"/> <descriptor
id="item" type="semantic" href="http://
alps.io/ iana/relations#item" rt="#BlogPosting"/>
<descriptor id="post" type="không an toàn"
href="http://alps.io/activitystrea.ms/verbs#post">
<descriptor href="#BlogPosting"/> </
descriptor> </
descriptor>

<descriptor id="BlogPosting" type="semantic"


href="http://alps.io/schema.org/BlogPosting">
<descriptor id="articleBody" type="semantic"
href="http://alps.io/schema.org/BlogPosting#articleBody">
<descriptor id="dateCreated" type="ngữ nghĩa"
href="http://alps.io/schema.org/BlogPosting#dateCreated"> </
descriptor> </
alps>

Thay vì có ba liên kết hồ sơ , một trong những đại diện của tôi chỉ có thể liên kết đến hồ
sơ này.

Một khách hàng không hiểu hồ sơ của tôi có thể coi các biểu diễn của tôi như các biểu diễn
HAL thuần túy. Điều này sẽ không hữu ích lắm vì HAL không tự xác định bất kỳ giao thức hoặc
ngữ nghĩa ứng dụng nào. Trình duyệt HAL có thể phân tích các biểu diễn của tôi và phân biệt
các liên kết với dữ liệu, nhưng nó sẽ không biết các liên kết hoặc dữ liệu có ý nghĩa gì.

Một số lời khuyên thiết kế

Hy vọng đến thời điểm này bạn đã hiểu rõ về quá trình thiết kế của tôi.
Bây giờ tôi muốn đưa ra một số bài học thực tế mà tôi đã học được từ việc phát triển và áp
dụng quy trình này.

Một số lời khuyên về thiết kế | 177


Machine Translated by Google

Tài nguyên là chi tiết triển khai Hầu hết các quy

trình thiết kế API web RESTful đều tập trung vào thiết kế tài nguyên. Nhưng không có tài nguyên ở

đây. Các hộp trong sơ đồ trạng thái không phải là tài nguyên, chúng là biểu diễn của tài nguyên—các
tài liệu thực tế được gửi qua lại giữa khách hàng và

máy chủ.

Đây không phải là một sự giám sát. Tài nguyên là yếu tố chính đối với HTTP và chúng rất quan trọng

đối với việc triển khai API, nhưng tôi nhận ra rằng thực chất chúng không quan trọng lắm đối với

REST. Quá trình thiết kế của tôi tập trung vào chuyển đổi trạng thái và mô tả ngữ nghĩa. Một khi

bạn đã xác định được những điều đó, bạn sẽ có được nguồn lực của mình.

Hãy nghĩ về HTTP qua lại giữa máy khách và máy chủ. Một tài nguyên nhận được yêu cầu GET và phục vụ

một đại diện với một loại phương tiện nhất định. Biểu diễn chứa các điều khiển hypermedia, mô tả

các chuyển đổi trạng thái có thể xảy ra. Máy khách kích hoạt chuyển đổi trạng thái bằng cách gửi

yêu cầu HTTP đến tài nguyên khác, thực hiện thay đổi trạng thái và gửi một đại diện khác. Máy khách

không bao giờ tương tác trực tiếp với một tài nguyên.

Nếu bạn đến bước 6 và nhận thấy mình cần triển khai một số tài nguyên ngoài dự kiến, tôi e rằng bạn

đã bỏ qua một bước. Tài nguyên bạn đang tưởng tượng cần được liên kết từ một số tài nguyên hiện có.

Liên kết đó là một quá trình chuyển đổi trạng thái và nó phải hiển thị trên một mũi tên trong sơ đồ

trạng thái của bạn (bước 2). Nếu tài nguyên quản lý trạng thái của chính nó thì nó cần có một biểu

diễn. Biểu diễn đó lẽ ra phải hiển thị dưới dạng một hộp trên sơ đồ trạng thái của bạn (bước 2).

Biểu diễn phải có loại phương tiện (bước 4) và có thể có hồ sơ (bước 5). Dữ liệu mà nó truyền đến

máy khách lẽ ra phải hiển thị trong danh sách lớn mà bạn đã lập ở bước 1. Nếu tài nguyên hỗ trợ bất

kỳ chuyển đổi trạng thái không an toàn nào thì những chuyển đổi đó sẽ hiển thị ở bước 2. Chúng phải

được mô tả bằng điều khiển siêu phương tiện được nhúng bên trong một số đại diện.

Nếu bạn chưa quyết định về ngữ nghĩa giao thức và ngữ nghĩa ứng dụng của tài nguyên thì bạn chưa

thực sự thiết kế nó. Nếu bạn đã quyết định những điều đó thì không còn gì khác để thiết kế.

Việc tập trung vào tài nguyên trước tiên sẽ không mang lại cho bạn một thiết kế tồi nhưng nó có xu

hướng thể hiện một thiết kế về mặt triển khai phía máy chủ hơn là về mặt trải nghiệm của khách hàng.

Cũng dễ dàng sử dụng thiết kế tài nguyên tốt (được hỗ trợ bởi rất nhiều tài liệu mà con người có

thể đọc được) như một cái cớ để tránh nghĩ về hypermedia.

Đừng rơi vào Bẫy Bộ sưu tập Mặc dù mẫu bộ sưu

tập rất chung chung và mạnh mẽ nhưng nó lại chứa một cái bẫy. Tôi đã chứng kiến cái bẫy này xuất

hiện hàng chục lần trong vài năm qua và lời khuyên mà tôi cân nhắc là đừng mắc bẫy. Đừng sử dụng

lược đồ cơ sở dữ liệu làm cơ sở cho thiết kế API của bạn.

Hãy vẽ sơ đồ trạng thái thay thế.

178 | Chương 9: Quy trình thiết kế


Machine Translated by Google

Thoạt nhìn, việc sử dụng lược đồ cơ sở dữ liệu có vẻ là một ý tưởng tuyệt vời. Cơ sở dữ liệu SQL,

với bốn lệnh cơ bản (CHỌN/CHÈN/CẬP NHẬT/XÓA) ánh xạ tự nhiên vào mẫu CRUD (tạo/truy xuất/cập nhật/

xóa), ánh xạ tự nhiên vào mẫu bộ sưu tập dành cho API, ánh xạ tự nhiên vào bốn phương thức HTTP chính

(GET/POST/PUT/DELETE). Không có lý do kỹ thuật nào khiến bạn không thể bỏ qua hầu hết quy trình của

tôi và xuất bản lược đồ cơ sở dữ liệu của mình thông qua mẫu bộ sưu tập. Điều gì có thể xảy ra?

Nhờ các công cụ hiện đại, chiến lược này sẽ nhanh chóng giúp bạn có được một API hoạt động được nhưng

nó có hai vấn đề lớn. Nguyên nhân đầu tiên xuất phát từ thực tế là người dùng của bạn không quan tâm

đến lược đồ cơ sở dữ liệu của bạn. Họ quan tâm đến ngữ nghĩa ứng dụng của bạn và cả hai chỉ liên quan

một cách mơ hồ. Bạn sẽ không thiết lập một trang web chỉ là một giao diện thô cho cơ sở dữ liệu của

mình. Bạn nên đặt suy nghĩ tương tự vào việc thiết kế API giống như cách bạn thiết kế một trang web.

Mặt khác, bạn quan tâm đến lược đồ cơ sở dữ liệu của mình—đến mức bạn có quyền thay đổi lược đồ khi

yêu cầu của bạn thay đổi. Đó là vấn đề thứ hai. Khi bạn xuất bản một API dựa trên lược đồ cơ sở dữ

liệu, về cơ bản, những thay đổi đối với lược đồ đó trở nên không thể thực hiện được. Bạn đã trao

quyền phụ thuộc phần mềm vào lược đồ cơ sở dữ liệu của mình cho hàng nghìn người mà bạn chưa từng

nghe tên. Những người này là khách hàng của bạn và hỗ trợ họ là trách nhiệm của bạn. Những thay đổi

đối với lược đồ, những thay đổi mà người dùng trang web của bạn thậm chí sẽ không nhận thấy, sẽ gây

ra những vấn đề lớn cho người dùng API của bạn.

Có tất cả các loại kỹ thuật để giải quyết những vấn đề này và tôi sẽ thảo luận về chúng trong “Khi

API của bạn thay đổi” ở trang 185. Nhưng chiến lược tốt nhất là tránh rơi vào tình huống này ngay từ

đầu.

Đó là một lý do khác khiến quy trình của tôi sử dụng sơ đồ trạng thái. Giữ bạn thoát khỏi cái bẫy

này là mối quan tâm lớn của tôi. Suy nghĩ về việc chuyển đổi trạng thái buộc bạn phải xem xét ứng

dụng của mình chứ không phải cơ sở dữ liệu chứa tất cả trạng thái tài nguyên.

Tôi không nói để tránh mô hình bộ sưu tập. Đó là một mô hình tuyệt vời. Nếu sơ đồ trạng thái của bạn

trông giống như Hình 9-7, hãy tiếp tục và sử dụng nó. Nhưng hãy vẽ sơ đồ trạng thái trước. Đừng nhầm

lẫn ngữ nghĩa giao thức do ứng dụng của bạn xác định với giao diện do cơ sở dữ liệu của bạn xác định.

Đừng bắt đầu với Định dạng trình bày Bạn có thể muốn chọn định

dạng trình bày trước khi bắt đầu bước 1, để bạn có thể hình dung tài liệu của mình sẽ trông như thế

nào khi bạn tìm ra ngữ nghĩa. Bạn có thể sử dụng định dạng chung như HTML để vẽ nguệch ngoạc, nhưng

tôi khuyên bạn nên tạm dừng quyết định cho đến khi bạn chuyển sang bước 4, dù chỉ là tạm thời. Đó là

vì các định dạng trình bày không chỉ là nơi chứa dữ liệu thụ động. Họ đưa ra các giả định về ngữ

nghĩa giao thức và ứng dụng vào mọi API sử dụng chúng. Những giả định này có thể xung đột với yêu

cầu kinh doanh của bạn.

Một số lời khuyên về thiết kế | 179


Machine Translated by Google

Lấy một ví dụ ngớ ngẩn, giả sử bạn bắt đầu thiết kế API bằng cách chọn sử dụng Mê cung +XML, chỉ vì đó là định

dạng trình bày đầu tiên mà tôi đã thảo luận chi tiết. Có lẽ bạn đang phạm sai lầm. Mê cung+XML xác định một sơ

đồ trạng thái rất cụ thể trông giống như sơ đồ trong Hình 9-6. Nó xác định một tập hợp ngữ nghĩa ứng dụng trong

đó các yêu cầu GET có nghĩa là “đi vào mê cung”, “di chuyển theo một hướng nhất định” hoặc “thoát khỏi mê

cung”. Nói tóm lại, Mê cung+XML dành cho trò chơi mê cung.

Bạn không thể chọn Mê cung+XML cho đến khi bạn thực hiện xong hai bước đầu tiên. Bạn cần phân tách các yêu cầu

kinh doanh của mình thành một tập hợp ngữ nghĩa giao thức và ngữ nghĩa ứng dụng. Nếu hóa ra chúng phù hợp với

ngữ nghĩa được xác định bởi Mê cung+XML thì điều đó thật tuyệt.

Nhưng có lẽ họ sẽ không làm vậy.

Để lấy một ví dụ ít ngớ ngẩn hơn, giả sử bạn bắt đầu bằng cách quyết định sử dụng Collection+JSON (hoặc AtomPub

hoặc OData) cho API của mình. Điều đó có nghĩa là bạn đã chọn một tập hợp ngữ nghĩa triển khai mẫu bộ sưu tập.

Bạn đang tuyên bố trước rằng sơ đồ trạng thái API của bạn trông giống như Hình 9-7.

Làm sao bạn có thể nói trước được điều đó? Nếu ngữ nghĩa giao thức của bạn phù hợp với mẫu bộ sưu tập (và chúng

thường như vậy), thì các tiêu chuẩn mẫu bộ sưu tập chính là thứ bạn cần. Nhưng bạn không thể cứ theo trực giác;

bạn thực sự cần phải vẽ sơ đồ trạng thái.

Tất nhiên, nếu việc sử dụng một định dạng trình bày cụ thể là một trong những yêu cầu kinh doanh của bạn, bạn

cũng có thể đưa ra quyết định đó trước tiên và thiết kế API của mình xung quanh định dạng trình bày bắt buộc.

Nếu API của bạn là một phần của hệ thống nhúng tiêu thụ điện năng thấp, bạn có thể phải xây dựng nó dựa trên

Định dạng Liên kết CoRE (xem Chương 13). Nếu bạn làm việc cho một công ty nằm trong Ủy ban Kỹ thuật OData và

đã triển khai 75 API OData (Chương 10), hãy đoán xem—bạn có thể đang thiết kế số

76.

Điều này không có nghĩa là API của bạn bị hỏng. Hypermedia mang đến cho bạn rất nhiều sự linh hoạt. Nếu cần,

bạn có thể triển khai bất kỳ API nào bạn muốn dưới dạng tiện ích mở rộng cho Mê cung+XML. Chỉ cần coi nó như

một ràng buộc bổ sung, bên cạnh các ràng buộc Fielding.

Thiết kế URL không quan trọng Một số hướng

dẫn thiết kế API, bao gồm cả Dịch vụ web RESTful ban đầu , dành nhiều thời gian để nói về các URL bạn nên gán

cho tài nguyên của mình. Mỗi URL bạn phân phối phải xác định rõ ràng tài nguyên theo cách mà con người nhìn vào

URL có thể tìm ra nội dung ở đầu bên kia.

Nếu bạn xuất bản một tài nguyên là tập hợp các tài khoản người dùng, nó sẽ được gọi là /users/. Các tài nguyên

cấp dưới phải được xuất bản bên dưới nguồn gốc của chúng. Vì vậy, tài nguyên đại diện cho tài khoản của Alice

phải được cung cấp một URL như /users/alice.

Vâng, đại loại thế.

180 | Chương 9: Quy trình thiết kế


Machine Translated by Google

Về mặt kỹ thuật, không có vấn đề gì trong số này. URL chỉ là địa chỉ của một tài nguyên mà khách

hàng có thể sử dụng để nhận thông tin đại diện. Về mặt kỹ thuật, URL không nói bất cứ điều gì về

tài nguyên hoặc cách trình bày của nó. Kiến trúc của World Wide Web, Tập Một diễn đạt như sau:

Thật thú vị khi đoán bản chất của một tài nguyên bằng cách kiểm tra URI xác định nó.

Tuy nhiên, Web được thiết kế sao cho các tác nhân truyền đạt trạng thái thông tin tài nguyên thông

qua các biểu diễn chứ không phải các mã định danh. Nói chung, người ta không thể xác định loại biểu

diễn tài nguyên bằng cách kiểm tra URI cho tài nguyên đó.

Điều này có nghĩa là việc tập hợp tài khoản người dùng có URL /0000000000000a và tập hợp đó liên kết

với tài khoản người dùng của Alice bằng URL /prime-numbers?how_many=200 là hoàn toàn hợp pháp. Điều

quan trọng là việc trình bày một tập hợp người dùng cho thấy rõ rằng nó đại diện cho một tập hợp

người dùng và việc trình bày tài khoản người dùng của Alice chứa thông tin về trạng thái của tập

hợp đó.
nguồn.

Khi bạn nhìn vào một URL và cố gắng hiểu tài nguyên cơ bản, bạn đang cố gắng tìm ra ngữ nghĩa cấp

ứng dụng của tài nguyên đó. Tốt rồi. Lời khuyên về thiết kế URL được đưa ra trong các cuốn sách và

hướng dẫn khác là lời khuyên hữu ích. Nhưng tôi sẽ không nhắc lại lời khuyên đó trong cuốn sách này,

vì tôi không muốn các API của bạn dựa vào URL để truyền tải ngữ nghĩa cấp ứng dụng của chúng. Chúng

tôi có những cách đáng tin cậy hơn để mô tả nội dung đó: định nghĩa loại phương tiện và cấu hình

máy có thể đọc được.

Đây là một ví dụ. Nhiều API ngày nay có các quy tắc xây dựng URL trong tài liệu mà con người có
thể đọc được:

URL tới tài khoản của người dùng trông như thế này:

/người dùng/{tên người dùng}

Về cơ bản đó là Mẫu URI. Nếu bạn cung cấp định dạng trình bày hỗ trợ Mẫu URI, bạn có thể thay thế

tài liệu đó bằng điều khiển siêu phương tiện tương đương.

Đây là một ví dụ ở định dạng Tài liệu gia đình JSON (tôi sẽ trình bày trong Chương 10):

"user_lookup": {"href-template": "/users/{username}",


"href-vars":
{ "username" : "http://alps.io/microformats/hCard#nickname"} }

Hầu như tất cả những thứ này đều có thể đọc được bằng máy đối với một máy biết cách phân tích Tài

liệu gia đình JSON. Điều duy nhất phải được giải thích bằng thuật ngữ mà con người có thể đọc được

là tên người dùng mô tả ngữ nghĩa. Điều đó có thể đi vào văn bản nội tuyến hoặc vào một hồ sơ có

thể đọc được bằng máy, chẳng hạn như hồ sơ Alps.io được liên kết ở đây.

Hầu hết các định dạng không chính thức hỗ trợ Mẫu URI nhưng chúng bao gồm một điều khiển siêu phương

tiện thực hiện điều gì đó tương tự—hãy nghĩ đến thẻ <form> của HTML với hành động="GET".

Bạn nhận được hai lợi ích lớn từ việc sử dụng các điều khiển này thay vì các điều khiển tương đương mà con người có thể

đọc được.

Một số lời khuyên về thiết kế | 181


Machine Translated by Google

Vì hypermedia có thể đọc được bằng máy nên người dùng của bạn có thể sử dụng thư viện chuẩn để

quản lý nó. Điều này giúp loại bỏ khả năng họ hiểu sai hướng dẫn văn xuôi của bạn.

Và vì hypermedia được phân phát trong thời gian chạy nên bạn có nhiều thời gian để thay đổi quyền

kiểm soát này mà không làm ảnh hưởng đến ứng dụng khách của mình—điều mà bạn không thể làm khi

thông tin tương tự được lưu giữ trong tài liệu API của bạn.

Một lần nữa, không có gì sai với những URL đẹp mắt. Các URL đẹp mắt thật tuyệt vời!

Nhưng chúng là mỹ phẩm. Họ trông tuyệt thật. Họ không làm gì cả. Ứng dụng khách API của bạn sẽ

tiếp tục hoạt động ngay cả khi tất cả các URL có giao diện đẹp mắt đột nhiên được thay thế bằng

các URL được tạo ngẫu nhiên.

Tên tiêu chuẩn có lẽ tốt hơn tên của bạn Giả sử ngữ nghĩa ứng

dụng của bạn bao gồm “tên của một người”. Bạn sẽ viết nó ra ở bước 1, bạn sẽ cố
gắng khớp nó vào một hệ thống phân cấp và đặt cho nó một tên tạm thời dựa trên
trường tương ứng trong lược đồ cơ sở dữ liệu hoặc mô hình dữ liệu của bạn. Một
cái gì đó như first_name, firstname, first-name, fn, first name, first, fname,
hoặc cung cấp en_name. Bước 1 như vậy là ổn. Nhưng khi đến bước 3, bạn cần nhìn
xung quanh, nhận thấy rằng có rất nhiều hồ sơ hiện có để mô tả tên của mọi người
và sử dụng một trong số đó.

Bạn có thể được gắn với những tên bạn đã chọn ở bước 1. Nhưng bạn không tự mình thực hiện API

này. Bạn đang làm điều này cho người dùng của mình.2 Trong sự nghiệp của mình, người dùng sẽ sử

dụng rất nhiều API khác nhau và họ sẽ được hưởng lợi từ việc không phải học 20 tên hơi khác nhau

cho cùng một thứ. Trước mắt, người dùng của bạn sẽ được hưởng lợi từ việc không phải tìm hiểu về

chi tiết triển khai nội bộ của bạn. Bạn cũng được hưởng lợi: bằng cách áp dụng tên tiêu chuẩn cho

các phần ngữ nghĩa ứng dụng phổ biến, bạn có thể thay đổi tên nội bộ mà không cần thay đổi API.

Nhưng nên chọn hồ sơ nào? Tiêu chuẩn hCard nói rằng bộ mô tả ngữ nghĩa cho tên riêng của một

người là tên riêng. Tiêu chuẩn xCard cho biết nó đã được cung cấp. Tiêu chuẩn FOAF cho biết đó là

GivenName, nhưng FirstName đó có thể được sử dụng khi diễn giải dữ liệu cũ. Mục Schema.org Person

chỉ cho phép GivenName. Đây là những tiêu chuẩn được xác định rõ ràng, được tôn trọng và xung đột

với nhau.

Điều đó thật khó chịu nhưng chẳng có lý do gì để bịa ra thêm nhiều cái tên và khiến tình hình trở

nên tồi tệ hơn. Chỉ cần chọn một cấu hình—bất kỳ cấu hình nào phù hợp nhất với ngữ nghĩa ứng dụng
API của bạn—và sử dụng các tên mà nó xác định.

Những người chịu trách nhiệm về các tiêu chuẩn này đã thực hiện các bước để tránh những cạm bẫy

về mặt khái niệm mà có thể bạn chưa từng cân nhắc. Ví dụ: “tên” không phải là một thuật ngữ chính

xác. Đó là một hiện vật của văn hóa phương Tây, trong đó chúng ta đặt tên của một người lên hàng

đầu. Ở một số nền văn hóa khác, tên gia đình đứng đầu. Chủ tịch hiện tại của Trung Quốc được nêu tên

2. Nếu bạn đang tự làm API này thì hãy làm bất cứ điều gì bạn muốn.

182 | Chương 9: Quy trình thiết kế


Machine Translated by Google

Tập Cận Bình. “Họ” của anh ấy là Tập Cận Bình. Đó là lý do tại sao tên được mô tả có ngữ nghĩa tốt
3
hơn tên.

Nếu bạn là người nói tiếng Anh bản xứ, có thể bạn đã không cân nhắc điều này. Và nếu lược đồ cơ sở

dữ liệu nội bộ của bạn có một trường tên là firstname thì điều đó không quan trọng lắm. Nhưng khi

bạn bắt đầu gửi dữ liệu của mình ra thế giới, việc bạn mô tả dữ liệu đó như thế nào sẽ rất quan trọng.

Các nhà thiết kế hCard, xCard, FOAF và Person của lược đồ.org đã cân nhắc điều này. Xem xét các vấn

đề phức tạp trong việc đặt tên là một phần công việc của họ. Đó là lý do tại sao tất cả các tiêu

chuẩn đó đều sử dụng cụm từ “tên riêng” làm cơ sở cho bộ mô tả ngữ nghĩa của chúng. Đó là lý do tại

sao FOAF nói rằng FirstName chỉ nên được sử dụng để diễn giải dữ liệu cũ. Nếu bạn quan tâm đến độ

nhạy cảm về văn hóa và/hoặc độ chính xác, bạn nên làm theo hướng dẫn của các hồ sơ hiện có. Bằng cách

áp dụng chúng bất cứ khi nào có thể, bạn sẽ hạn chế được tần suất phải thực hiện công việc đặt tên phức tạp.

Nếu bạn thiết kế loại phương tiện Ưu

điểm của loại phương tiện mới là khả năng kiểm soát hoàn toàn mà nó mang lại cho bạn về cách khách

hàng xử lý tài liệu của bạn. Bạn không cần phải dựa trên API của mình dựa trên XML, JSON hoặc HTML.

Bạn có thể khai báo một định dạng tệp nhị phân hoàn toàn mới và đưa ra hướng dẫn từng byte về cách

xử lý nó. Bạn không cần phải tìm kiếm các hồ sơ phản ánh ngữ nghĩa ứng dụng của mình. Dù bạn nói gì,

đi.

Nhiều tổ chức có định dạng tệp dựa trên XML hoặc JSON được thiết kế để sử dụng nội bộ và chưa bao

giờ được chỉ định chính thức. Sẽ không mất nhiều công sức để biến các định dạng đó thành các loại

siêu phương tiện dành riêng cho miền mà người ngoài có thể sử dụng được.4 Công việc là công việc viết

đặc tả chính thức đó. Loại phương tiện phải đi kèm với hướng dẫn xử lý đầy đủ, rõ ràng.

Nếu bạn thấy mình phải xác định 5 hoặc 10 loại phương tiện cho một API thì đó là một dấu hiệu xấu.

Thay vào đó, bạn nên sử dụng loại siêu phương tiện chung hoặc bạn nên xác định một loại phương tiện

mới, cùng với một số quy tắc để áp dụng tài liệu ALPS (hoặc định dạng hồ sơ khác) cho loại phương

tiện đó. 5 hoặc 10 bit ngữ nghĩa khác nhau đó có thể tạo thành 5 hoặc 10 cấu hình.

Mọi loại phương tiện mới đều cần có tên và RFC 6838 giải thích cách đặt tên cho chúng. Có thể bạn sẽ

có một cái tên như application/vnd.yourcompany.type-name. Loại phương tiện dựa trên JSON hoặc XML

phải có hậu tố +json hoặc +xml, la vnd.amund sen.application/maze+xml.

3. Tên riêng từng được gọi là “tên Kitô giáo”: tên được đặt như một phần của nghi lễ rửa tội cho trẻ sơ sinh.

Thuật ngữ đó là một tạo tác của văn hóa Công giáo châu Âu. Không phải tất cả mọi người trên thế giới đều trải qua buổi lễ đó (tôi chưa bao

giờ làm vậy), vì vậy chúng tôi chuyển sang một thuật ngữ tổng quát hơn. Sau đó chúng tôi lại đổi chỗ.

4. Nhưng cũng sẽ không mất nhiều công sức để chuyển đổi định dạng JSON đó sang Hydra, một định dạng mà tôi sẽ trình bày trong Chương 12.

Một số lời khuyên về thiết kế | 183


Machine Translated by Google

Nếu bạn mong muốn những người bên ngoài tổ chức của mình chuyển các tài liệu sử dụng loại phương

tiện của bạn thì bạn cũng cần cho cả thế giới biết cách xử lý các tài liệu đó.

Điều này có nghĩa là đăng ký loại phương tiện của bạn với IANA.

Đăng ký là một thủ tục khá chính thức, được mô tả trong phần 4 và 5 của RFC 6838.

Về cơ bản, bạn đang thông báo cho IANA (và tất cả những người sử dụng loại phương tiện của bạn sau

đó) nơi tìm mô tả về loại phương tiện và liệu nó có tạo ra bất kỳ mối lo ngại bảo mật đặc biệt nào

hay không. Bạn có thể đăng ký loại phương tiện bằng cách điền vào biểu mẫu.

Dưới đây là những điều chính cần xem xét khi điền vào biểu mẫu đó:

• Bạn phải có “thông số kỹ thuật công khai vĩnh viễn và sẵn có về định dạng dành cho loại phương

tiện truyền thông”. Nó cần bố trí định dạng đủ chi tiết để ai đó có thể viết trình phân tích

cú pháp cho định dạng dữ liệu của bạn, chỉ sử dụng thông tin trong phần cụ thể.
cation.

Bạn có thể đang lên kế hoạch tạo định nghĩa loại phương tiện “có sẵn” như một phần tài liệu

API của mình. Nhưng IANA muốn mức độ chi tiết có thể hiệu quả hơn bạn mong đợi. Công việc này

là cần thiết vì khi bạn đăng ký một loại phương tiện, những người chưa bao giờ nghe nói đến

bạn, những người không có kết nối với API của bạn, sẽ truy cập trang web của bạn và đọc thông

số kỹ thuật của bạn để họ có thể tạo tài liệu của riêng họ ở định dạng bạn đã xác định. • Bạn

sẽ cần đề cập đến bất kỳ mối lo ngại nào về bảo mật liên quan đến việc

xử lý tài liệu trong loại phương tiện của bạn. Điều này đặc biệt quan trọng nếu tài liệu của bạn

có thể bao gồm mã thực thi.

RFC 6838 có danh sách kiểm tra cơ bản về những điều cần xem xét ở đây. Nếu loại phương tiện

của bạn dựa trên JSON, bạn cũng nên tham khảo phần 6 của RFC 4627, trong đó mô tả các mối lo

ngại về bảo mật liên quan đến chính JSON. •

Nếu loại phương tiện của bạn dựa trên XML, bạn sẽ cần phải thực hiện một số tác vụ đặc biệt, được

mô tả trong phần 7.1 của RFC 3023. Các tác vụ này chủ yếu liên quan đến việc thêm bản soạn

sẵn dành riêng cho XML vào nội dung gửi của

bạn. • Nếu loại phương tiện của bạn không dựa trên XML, bạn sẽ cần chỉ định cách dữ liệu có thể

xuất hiện qua mạng. Câu trả lời thường sẽ là “nhị phân”. Đối với các loại phương tiện dựa trên

JSON, bạn có thể tham khảo tiêu chuẩn JSON, RFC 4627 hoặc chỉ nói “nhị phân”. Nếu loại phương

tiện của bạn dựa trên XML thì bản soạn sẵn từ RFC 3023 sẽ đảm nhiệm phần này.

• Có lẽ bạn nên xác định tham số cấu hình cho loại phương tiện của mình để khách hàng có thể yêu

cầu một cấu hình cụ thể bằng cách sử dụng tiêu đề Kiểu nội dung . (Tôi đã thảo luận thủ thuật

này trong Chương 8.) Đây là ý kiến của tôi, không phải một phần của RFC 6838. Bạn chỉ có thể

nói rằng loại phương tiện của bạn nhận tham số hồ sơ và giá trị của nó là URI của hồ sơ, theo

RFC 6906.

184 | Chương 9: Quy trình thiết kế


Machine Translated by Google

Nếu bạn muốn nhận lời khuyên từ cộng đồng trước khi gửi bài, hãy gửi những gì bạn nhận được dưới dạng email tới

media-types@iana.org. Nếu bạn muốn xem một ví dụ đơn giản, hãy xem đăng ký đã được phê duyệt cho loại phương tiện

Mê cung+XML.

Bạn không cần phải đăng ký loại của mình với IANA nếu bạn không muốn. Nếu bạn quyết định không đăng ký, bạn sẽ

cần sử dụng vnd. tiền tố (đối với một dự án thương mại—dù sao thì đây cũng có thể là tiền tố mà bạn có thể đang

sử dụng) hoặc prs . tiền tố (đối với một dự án cá nhân hoặc công việc thử nghiệm). Nhưng nếu loại phương tiện của

bạn nói chung trở nên phổ biến, bạn thực sự nên đăng ký nó. Hàng trăm loại phương tiện dành riêng cho nhà cung

cấp, như application/vnd.ms-powerpoint, được đăng ký với IANA.

Khi API của bạn thay đổi Một trong

những chủ đề được tranh luận sôi nổi nhất hiện nay trong cộng đồng API là lập phiên bản. Đó là một vấn đề lớn.

Hầu hết các công ty đưa ra API không bao giờ thay đổi API đó sau lần phát hành đầu tiên. Họ không thể làm điều đó.

Nói thẳng ra, họ không thể làm điều đó vì họ đã bỏ qua ràng buộc về hypermedia. Hầu hết các API đưa giao thức và

ngữ nghĩa ứng dụng của chúng vào tài liệu mà con người có thể đọc được. Sau đó, người dùng các API đó sẽ viết một
loạt phần mềm máy khách dựa trên tài liệu đó.

Bây giờ các nhà cung cấp API đang bị kẹt. Họ có thể thay đổi tài liệu nhưng làm như vậy sẽ không tự động thay đổi

hành vi của tất cả khách hàng đó. Họ đã trao cho người dùng quyền phủ quyết đối với bất kỳ thay đổi nào trong

thiết kế của họ.

Tuy nhiên, việc thay đổi tài liệu hypermedia sẽ thay đổi hành vi của mọi khách hàng nhận được nó. Đó là lý do tại

sao một trang web có thể được thiết kế lại toàn bộ mà không làm hỏng trình duyệt web của mọi người. Một trang web

hoàn toàn được chứa trong các đại diện mà nó phục vụ. Không có gì ẩn thêm trong tài liệu mà con người có thể đọc

được.

Đây là thời điểm mà rất nhiều đề xuất tôi đưa ra trong cuốn sách này – những đề xuất ban đầu có vẻ mô phạm và soi

mói – thực sự bắt đầu có hiệu quả. Một trong những mục tiêu chính của tôi là giảm số lượng tài liệu mà con người

có thể đọc được đi kèm với API của bạn. Điều đó không chỉ vì tài liệu mà con người có thể đọc được dễ bị hiểu

sai. Đó là bởi vì việc thay đổi một phần tài liệu mà con người có thể đọc được đòi hỏi phải có sự thay đổi tương

ứng trong mỗi đoạn mã dựa trên tài liệu đó.

Việc chuyển ngữ nghĩa API của bạn ra khỏi tài liệu mà con người có thể đọc được và vào các tài liệu siêu phương

tiện giúp API của bạn trở nên linh hoạt hơn khi đối mặt với sự thay đổi. Chọn một định dạng hypermedia tốt và bạn

có thể thêm tài nguyên mới cũng như chuyển đổi trạng thái vào API của mình mà không ảnh hưởng đến các máy khách

hiện tại. Bạn cũng sẽ có khá nhiều chỗ để thay đổi ngữ nghĩa giao thức của mình.

Lý tưởng nhất là việc thiết kế lại một API cũng dễ dàng như việc thiết kế lại một trang web. Có lẽ chúng ta sẽ

không bao giờ đạt được điều đó, vì lý do tương tự, chúng ta sẽ không bao giờ thu hẹp được hoàn toàn khoảng cách

ngữ nghĩa. Nếu bạn thêm một trường bắt buộc mới vào quá trình chuyển đổi trạng thái, bạn có thể thêm một bộ mô

tả ngữ nghĩa mới vào hồ sơ máy có thể đọc được của mình, nhưng vẫn cần phải có phần giải thích về bộ mô tả ngữ nghĩa đó.

Một số lời khuyên về thiết kế | 185


Machine Translated by Google

để được giải thích bởi một con người. Một máy khách hoàn toàn tự động có thể hiểu được thông báo lỗi mà nó

đột nhiên bắt đầu nhận được—“Bạn không cung cấp giá trị cho re quired_field.”—nhưng nó sẽ không biết nên

gửi giá trị nào cho require_field.

Ngoài ra còn có những thay đổi mà ứng dụng khách lý tưởng sẽ thích ứng, nhưng điều đó có thể làm hỏng ứng

dụng khách thực, chẳng hạn như thay đổi điều khiển siêu phương tiện để sử dụng PUT thay vì POST. Nhưng nhìn

chung, bạn sẽ thành công hơn khi thay đổi một chút ngữ nghĩa nếu nó được mô tả ở dạng máy có thể đọc được
điều kiện.

Nếu bạn thay đổi một tài nguyên và khách hàng của bạn không thể tự động thích ứng với thay đổi đó, bạn sẽ

cần dành một khoảng thời gian để xuất bản một cách hiệu quả hai tài nguyên khác nhau—một tài nguyên cũ và

một tài nguyên mới—với ngữ nghĩa giao thức hoặc ứng dụng khác nhau. Có ba chiến lược phổ biến để làm điều

này.

Phân vùng không gian URL Trong

kỹ thuật lập phiên bản phổ biến nhất, toàn bộ API được chia thành hai API riêng biệt.

Đôi khi hai API có các URL biển quảng cáo khác nhau, như http://api-v1.example. com/ và http://api-

v2.example.com/.

Đôi khi chỉ có một URL biển quảng cáo, nhưng việc trình bày biển quảng cáo sử dụng siêu phương tiện để cung

cấp cho khách hàng sự lựa chọn giữa các phiên bản:

<ul>
<li><a class="v1" href="/v1/">Phiên bản 1</a></li>
<li><a class="v2" href="/v2/">Phiên bản 2</ a></li>
</ul>

Ở đây, số phiên bản là một bộ mô tả ngữ nghĩa. Khách hàng không biết v2 nghĩa là gì sẽ không theo liên kết.

Việc phân vùng có hiệu quả vì các biểu diễn được tìm thấy bên dưới /v1 chỉ liên kết đến các tài nguyên được

tìm thấy bên dưới /v1. Cả hai phiên bản API có thể sử dụng cùng một mã cơ bản, nhưng chúng có thể có ngữ

nghĩa ứng dụng hoàn toàn khác nhau, bởi vì bất kỳ khách hàng cụ thể nào cũng sẽ chỉ sử dụng cái này hoặc

cái kia.

Lập phiên bản loại phương

tiện Nếu bạn đã xác định loại phương tiện dành riêng cho miền cho ứng dụng của mình, bạn có thể cung cấp

cho nó một tham số phiên bản . Sau đó, khách hàng có thể sử dụng đàm phán nội dung (xem Chương 10) để yêu
cầu phiên bản này hay phiên bản khác:

Chấp nhận: application/vnd.myapi.document?version=2

Tôi không nghĩ bạn nên xác định loại phương tiện dành riêng cho tên miền ngay từ đầu, nhưng ngay cả khi bạn

làm vậy thì đây vẫn là một ý tưởng tồi. Loại phương tiện của bạn không phải là API của bạn. Đây là một thử

nghiệm suy nghĩ: liệu một công ty khác có thể sử dụng loại phương tiện của bạn trong API không liên quan

của riêng họ không? Họ có nhận được lợi ích nào từ việc đó không, ngoài khả năng tương thích với tiêu chuẩn

tiền pháp định của bạn? Nếu không có lý do thuyết phục nào để người khác chấp nhận loại phương tiện của bạn

thì tức là bạn đã đặt quá nhiều API vào định nghĩa loại phương tiện của mình.

186 | Chương 9: Quy trình thiết kế


Machine Translated by Google

Loại phương tiện của bạn có xác định mọi khía cạnh của giao thức API và ngữ nghĩa ứng dụng như

cách Maze+XML thực hiện không? Nếu vậy thì việc thêm tham số phiên bản sẽ có tác dụng. Theo định

nghĩa, sự thay đổi về ngữ nghĩa có nghĩa là sự thay đổi về loại phương tiện. Nhưng nếu bạn giữ

một hồ sơ hoặc bất kỳ tài liệu nào mà con người có thể đọc được ngoài định nghĩa loại phương tiện,

thì có thể bạn sẽ thay đổi API mà không thay đổi định nghĩa loại phương tiện.

Sau đó, bạn sẽ gặp vấn đề: thuộc tính phiên bản thực sự áp dụng cho cái gì? Đây là loại phương

tiện hay API?

Các loại phương tiện được tiêu chuẩn hóa không làm điều này. HTML 5 rất khác với HTML 4, nhưng cả

hai đều được dùng dưới dạng văn bản/html và HTML 5 gần như tương thích ngược với HTML 4.5

Lập phiên bản hồ sơ

Tôi khuyên bạn nên căn cứ API của mình xung quanh loại phương tiện được tiêu chuẩn hóa và rõ ràng

là bạn không thể truy cập và khai báo phiên bản mới của loại phương tiện của người khác. Nhưng tôi

cũng khuyên bạn nên xác định ngữ nghĩa ứng dụng của mình trong một cấu hình mà máy có thể đọc được

và bạn có thể khai báo một phiên bản mới của cấu hình.

Hồ sơ của bạn tách biệt rõ ràng các phần của ứng dụng sẽ làm hỏng ứng dụng khách khi chúng thay

đổi (vì chúng được mô tả bằng văn bản mà con người có thể đọc được) khỏi các phần mà máy khách có

thể thích ứng (vì chúng được mô tả bằng hypermedia). Việc giữ hai cấu hình cho phép bạn giữ hai

bộ ngữ nghĩa ứng dụng. Khách hàng có thể sử dụng tiêu đề Liên kết để yêu cầu hồ sơ này hoặc hồ sơ

khác. Hoặc, nếu loại phương tiện hỗ trợ tham số hồ sơ , khách hàng có thể sử dụng tiêu đề Kiểu nội

dung và thực hiện đàm phán nội dung thông thường.

Versoning không phải

là phiên bản API đặc biệt nhận được nhiều sự chú ý vì vấn đề còn tồi tệ hơn nhiều đối với một API

bỏ qua ràng buộc hypermedia. Nhưng đó chỉ là một ví dụ về vấn đề chung được giải quyết bởi

hypermedia. Làm thế nào để khách hàng biết tài nguyên nào có đại diện mà họ muốn? Sau khi khách

hàng nhận được thông tin đại diện, làm thế nào để biết được thông tin đại diện đó có ý nghĩa gì?

Các kỹ thuật tôi đưa ra trước đó là các kỹ thuật mà máy chủ sử dụng nói chung khi cho khách hàng

lựa chọn giữa các cách biểu diễn.

Một máy chủ có thể đưa ra các liên kết đến hai URL khác nhau và máy khách có thể chọn liên kết nào

để theo dõi dựa trên sự hiểu biết về ngữ nghĩa của ứng dụng. Điều này giống nhau cho dù hai URL

trỏ đến các tài nguyên hoàn toàn khác nhau hay tới phiên bản v1 và v2 của một tài nguyên cơ bản.

Một tài nguyên có thể có các đại diện trong các loại phương tiện khác nhau. Máy khách có thể chọn

cách thể hiện mà nó muốn bằng cách sử dụng đàm phán nội dung (với tiêu đề Chấp nhận ;

5. Phiên bản 3.0 của HTML, vào năm 1995, thực sự đã làm được những gì API đang làm hiện nay. Nó giới thiệu một tham số phiên

bản và gợi ý rằng các tài liệu HTML nên được phân phát dưới dạng text/html;version=3.0. Điều này đã bị loại bỏ trong HTML

4. Khả năng tương thích ngược hoạt động tốt hơn.

Một số lời khuyên về thiết kế | 187


Machine Translated by Google

xem Chương 11) hoặc hypermedia. Điều này giống nhau cho dù các loại phương tiện hoàn toàn khác nhau

(Bộ sưu tập+JSON và HTML) hay chúng chỉ khác nhau ở tham số phiên bản . Tôi nghĩ tham số phiên bản

là một ý tưởng tồi, nhưng nếu bạn sử dụng nó, nó sẽ hoạt động giống như khi bạn sử dụng hai loại

phương tiện hoàn toàn khác nhau.

Một tài nguyên có thể được mô tả bằng nhiều cấu hình khác nhau và khách hàng có thể sử dụng đàm

phán nội dung hoặc siêu phương tiện để chọn tài nguyên mà nó muốn. Điều này giống nhau cho dù các

cấu hình là những cách tiếp cận khác nhau cho cùng một ý tưởng (hCard so với Person của lược đồ.org)

hay chúng là các cấu hình “v1” và “v2” của một API duy nhất.

Có một kế hoạch cuối cùng

thì việc lập phiên bản không phải là một vấn đề kỹ thuật. Đó là một khía cạnh trong mối quan hệ của

bạn với người dùng. Bạn không muốn một thay đổi nhỏ làm hỏng phần mềm máy khách của mọi người, vì

vậy, bạn mô tả càng nhiều thay đổi càng tốt bằng cách sử dụng siêu phương tiện có thể đọc được bằng

máy thay vì tài liệu mà con người có thể đọc được. Khi bạn phải thay đổi ngữ nghĩa của tài nguyên

theo cách phá vỡ tính tương thích ngược, bạn sẽ tạo phiên bản thứ hai của tài nguyên đó để khách

hàng mới sử dụng. Phiên bản thứ hai có thể được xác định bằng một URL khác, loại phương tiện khác

hoặc bất kỳ thứ gì. Khách hàng chưa sửa đổi vẫn có thể sử dụng phiên bản cũ.

Cuối cùng, bạn muốn thoát khỏi phiên bản cũ. Suy cho cùng, nếu bạn thích chức năng cũ thì bạn đã

không thay đổi nó. Một lần nữa, không có giải pháp kỹ thuật ở đây. Vấn đề là mối quan hệ của bạn

với người dùng của bạn. Bạn cần đặt ra kỳ vọng về thời điểm một phiên bản API của bạn sẽ không được

dùng nữa và khách hàng có thể mong đợi tiếp tục sử dụng API không được dùng trong bao lâu.

Khi bạn xuất bản API của mình, hãy đưa ra một số mức độ đảm bảo về thời gian hiệu lực của API. Bạn

có thể đưa ra lời đảm bảo trọn đời (“Chúng tôi sẽ tiếp tục hỗ trợ API này trong 5 năm.”) hoặc bạn

có thể đưa ra lời đảm bảo về thông báo (“Chúng tôi sẽ đưa ra cảnh báo một năm cho bạn trước khi

chúng tôi ngừng hỗ trợ API này.”) Đồng thời thiết lập một kênh liên lạc cụ thể để liên lạc về vấn

đề này: một trang web hoặc danh sách gửi thư.

Khi bạn muốn thực hiện một thay đổi đối với API làm hỏng khả năng tương thích ngược, đây là một quy

trình từng hiệu quả với tôi trước đây:

1. Khai báo phiên bản hiện tại “không được dùng nữa”. Nó vẫn sẽ hoạt động, nhưng nó không còn là

phiên bản hiện tại nữa. Thông báo điều này trên kênh liên lạc mà bạn thiết lập cho mục đích

này. Cập nhật tài liệu và hướng dẫn của bạn để các nhà phát triển mới bắt đầu sử dụng phiên

bản hiện tại chứ không phải phiên bản không được dùng nữa.

2. Sau một thời gian, hãy sử dụng kênh liên lạc để thông báo rằng bạn sẽ không sửa lỗi trên API

“không được dùng nữa” và nhắc nhở người dùng về phiên bản mới.

3. Sau một khoảng thời gian không sửa lỗi, hãy thông báo thời hạn sau đó "không được dùng nữa"
API sẽ bị tắt.

4. Có thể bạn sẽ cần thời gian gia hạn sau thời hạn, nhưng tại một thời điểm nào đó sau thời hạn,

hãy tắt API cũ. Yêu cầu sẽ dẫn đến mã trạng thái HTTP 410

188 | Chương 9: Quy trình thiết kế


Machine Translated by Google

(Đã qua), cùng với nội dung thực thể HTML giải thích đây là API đã chết và liên kết đến phiên
bản hiện tại.

Tốc độ bạn có thể thực hiện các bước này tùy thuộc vào quy mô cơ sở người dùng của bạn và tốc độ

trung bình mà cộng đồng của bạn có thể thay đổi. Việc thay đổi API ngân hàng sẽ mất nhiều thời

gian; việc thay đổi API blog sẽ nhanh hơn.

Nghe có vẻ không vui lắm phải không? Vâng, thật kinh khủng! Nhưng đây là cách bạn triển khai phần

mềm máy chủ mới mà không làm hỏng tất cả các máy khách đã triển khai mà bạn không có quyền kiểm soát.

Đó là lý do tại sao hypermedia lại quan trọng đến vậy. Bạn càng đưa được nhiều giao thức và ngữ

nghĩa ứng dụng vào dạng máy có thể đọc được thì bạn càng có nhiều khả năng thay đổi API của mình

mà không phải trải qua quá trình chậm chạp, rườm rà này.

Đừng giữ tất cả Hypermedia ở một nơi Một trong những tính

năng xác định của các API kiểu cũ, không phải RESTful là tài liệu mô tả dịch vụ. Đây là một tài

liệu lớn (thường ở định dạng WSDL) cung cấp mô tả đầy đủ về ngữ nghĩa ứng dụng và giao thức của

API. Tệp thường được tạo bởi một công cụ nút nhấn hiểu API dựa trên ý nghĩa phía máy chủ của nó.

tâm lý.

Người dùng có thể tải xuống tài liệu mô tả dịch vụ và sử dụng nó để tự động tạo ra bản triển khai

ứng dụng khách tương ứng. Họ có thể sử dụng ứng dụng khách để thực hiện các lệnh gọi API từ xa như

thể chúng là các lệnh gọi bằng ngôn ngữ lập trình cục bộ. Không cần phải hiểu gì về hypermedia, các

định dạng biểu diễn hoặc HTTP. Và sau đó sẽ có điều gì đó thay đổi trong quá trình triển khai phía

máy chủ và toàn bộ mọi thứ sẽ sụp đổ.

Vấn đề với thiết kế này là nó tạo ra sự kết hợp chặt chẽ giữa việc triển khai API phía máy chủ, mô

tả mà máy có thể đọc được và ứng dụng khách được tạo từ mô tả mà máy có thể đọc được đó. Khi việc

triển khai phía máy chủ thay đổi, thay đổi đó sẽ không được phản ánh trong ứng dụng khách được tạo

và ứng dụng khách sẽ bị hỏng.

Bây giờ, có thể bạn chưa nghĩ đến việc tạo mô tả WSDL cho API của mình.

Nhưng tài liệu API truyền thống thực sự là tài liệu mô tả dịch vụ mà con người có thể đọc được. Đó

là một tệp lớn giải thích ngữ nghĩa giao thức và ứng dụng của API.
Tài liệu mà con người có thể đọc được dễ hiểu hơn tệp WSDL, nhưng nó có cùng một vấn đề. Một thay

đổi đối với việc triển khai phía máy chủ sẽ dẫn đến thay đổi đối với “tài liệu dịch vụ”, nhưng thay

đổi đó không được truyền đến các máy khách đã triển khai. Các khách hàng phá vỡ.

API dựa trên hypermedia có khả năng hạn chế trong việc thể hiện các thay đổi phía máy chủ mà không

làm hỏng máy khách. Nhưng bạn không tự động có được khả năng này; bạn phải làm việc cho nó. Hoàn

toàn có thể viết một “tài liệu mô tả dịch vụ” mà máy có thể đọc được bằng HTML.

Trên Web, chúng tôi gọi đó là sơ đồ trang web. Sơ đồ trang web là bản mô tả đầy đủ về trang web

Một số lời khuyên về thiết kế | 189


Machine Translated by Google

ngữ nghĩa giao thức, tất cả trong một tài liệu. Bạn có thể tự động tạo ứng dụng khách API dựa

trên sơ đồ trang web HTML. Và khi việc triển khai phía máy chủ thay đổi, ứng dụng khách của bạn

sẽ bị hỏng vì nó dựa trên bản đồ lỗi thời.

Máy khách sử dụng API hypermedia không thể mong đợi biết trước về tất cả các chuyển đổi trạng

thái có thể xảy ra. Nó cần được thiết kế giống như một công cụ giải mê cung, có khả năng đưa ra

quyết định dựa trên các bước tiếp theo có thể được máy chủ trình bày trong thời gian chạy. Đó là

lý do tại sao tôi khuyên bạn nên chia nhỏ các điều khiển hypermedia của mình để mỗi biểu diễn,

khi được phục vụ, đều chứa các điều khiển có liên quan đến ứng dụng hiện tại và trạng thái tài

nguyên. Điều này sẽ buộc các nhà phát triển ứng dụng khách phải tính đến hypermedia, thay vì giả

vờ rằng họ có thể bỏ qua nó.

Tôi đưa ra vấn đề này vì có các công cụ nút bấm sẽ kiểm tra việc triển khai máy chủ của bạn và

tạo API cho bạn, một API được mô tả bằng tài liệu dịch vụ dựa trên hypermedia. Không có gì sai về

mặt kỹ thuật với điều này—hypermedia trong tài liệu dịch vụ vẫn là hypermedia—nhưng nó sẽ khuyến

khích người dùng của bạn đặt niềm tin vào ý tưởng rằng tài liệu dịch vụ sẽ không thay đổi. Ban

đầu mọi thứ có vẻ ổn, nhưng khi API của bạn phát triển, bạn sẽ bắt đầu gặp vấn đề. Bạn sẽ đánh

dấu vào hộp tính năng có nhãn “hypermedia”, nhưng bạn sẽ không thực sự nhận được những lợi ích từ

việc áp dụng hypermedia.

Bất kỳ định dạng hypermedia nào cũng có thể được sử dụng để viết một tài liệu dịch vụ, nhưng có

ba định dạng đặc biệt phù hợp với mô hình phản mẫu này. Chúng là OData và WADL (tôi sẽ đề cập đến

trong Chương 10) và Hydra (tôi sẽ đề cập đến trong Chương 12). Khi trình bày chúng, tôi sẽ nhắc

bạn về lời cảnh báo trước này.

Thêm Hypermedia vào API hiện có


Giả sử bạn đã thiết kế và triển khai một API. Đó là một API điển hình cho các thiết kế ngày nay,

một tiêu chuẩn fiat phục vụ các biểu diễn JSON hoặc XML đặc biệt, không có siêu phương tiện:

{ "name": "Jennifer Gallegos",


"bday": "25-08-1987" }

Bạn sẽ có thể nâng cấp API của mình lên mức chất lượng mà tôi đề xuất trong cuốn sách này mà không

làm ảnh hưởng đến các khách hàng hiện tại của bạn. Đây là phiên bản sửa đổi của quy trình bảy

bước mà tôi đã trình bày trước đó để sửa chữa API dựa trên JSON:

1. Ghi lại tất cả các tuyên bố hiện có của bạn. Mỗi cái sẽ chứa một số mô tả ngữ nghĩa. Bạn

không thể thay đổi những điều này, nhưng bạn có thể thêm mới
những cái đó.

190 | Chương 9: Quy trình thiết kế


Machine Translated by Google

2. Vẽ sơ đồ trạng thái cho API của bạn. Các hộp trên sơ đồ là sự thể hiện hiện có của bạn. Bạn có thể sẽ không

có bất kỳ chuyển đổi trạng thái nào vì hầu hết các API hiện có đều không có bất kỳ liên kết hypermedia nào.

Bây giờ là lúc để thêm một số. Sử dụng các mũi tên để kết nối các cách trình bày theo cách có ý nghĩa. Tên

của các mũi tên là mối quan hệ liên kết của bạn.

Tại thời điểm này, có thể một số bộ mô tả ngữ nghĩa của bạn thực sự là các mối quan hệ liên kết:

{ "trang chủ": "http://example.com" }

Bạn có thể chuyển đổi chúng thành quan hệ liên kết tại thời điểm này, nhưng hãy đảm bảo không đổi tên chúng

khi bạn chuyển sang bước tiếp theo.

3. Bạn không thể thay đổi tên của bất kỳ thứ gì bạn đã viết ở bước 1 vì điều đó sẽ ảnh hưởng đến khách hàng hiện

tại của bạn. Tuy nhiên, bạn có thể xem qua các mối quan hệ liên kết mà bạn đã tạo ở bước 2 và đảm bảo tên của

chúng đến từ IANA và các nguồn nổi tiếng khác bất cứ khi nào có thể.

4. Bạn không thể thay đổi loại phương tiện của mình vì điều đó sẽ làm hỏng ứng dụng khách của bạn. Nó sẽ có

để ở lại ứng dụng/json (hoặc bất cứ thứ gì hiện tại).

5. Vì bạn không thể thay đổi loại phương tiện nên tất cả ngữ nghĩa ứng dụng và ngữ nghĩa giao thức của bạn phải

được xác định ở một nơi khác. Bạn có hai lựa chọn: cấu hình ALPS hoặc bối cảnh JSON-LD.

Nếu bạn đã viết ra bất kỳ mối quan hệ liên kết không an toàn nào ở bước 2, lựa chọn tốt nhất của bạn là JSON-

LD với Hydra (xem Chương 12). Bạn sẽ có thể lấy các mô tả mà con người có thể đọc được về lệnh gọi API và

chuyển đổi chúng thành các hoạt động Hydra có thể đọc được bằng máy.

6. Bạn đã viết gần hết mã rồi. Bạn chỉ cần mở rộng từng cách trình bày bằng cách cung cấp các liên kết thích hợp.

7. URL biển quảng cáo của bạn sẽ giống như trước đây. Nếu trước đây bạn chưa có tài nguyên này vì API của bạn là

một nhóm các lệnh gọi API riêng biệt, bạn có thể tạo một tài nguyên mới để hoạt động như trang chủ của mình

và biết rằng chỉ những khách hàng nhận biết được siêu phương tiện mới có thể truy cập vào tài nguyên đó.

Sửa lỗi API dựa trên XML Quy trình tương tự

đối với API phục vụ các biểu diễn XML. Bạn có thể sử dụng XLink và XForm (xem Chương 12) để thêm các điều khiển

siêu phương tiện vào bất kỳ tài liệu XML nào.

Ở bước 2, khi bạn phát hiện ra rằng một trong những bộ mô tả ngữ nghĩa của bạn sẽ có ý nghĩa hơn dưới dạng mối

quan hệ liên kết, như trang chủ ở đây…

<homepage>http://example.com/</homepage>

Thêm Hypermedia vào API hiện có | 191


Machine Translated by Google

…bạn không thể chuyển đổi nó thành quan hệ liên kết. Điều đó sẽ phá vỡ khách hàng hiện tại của bạn.

Bạn sẽ cần phải thêm dự phòng. Ví dụ này sử dụng XLink để sử dụng trang chủ vừa là mối quan hệ

liên kết (xlink:arcrole) vừa là bộ mô tả ngữ nghĩa:

<trang chủ xlink:href="http://example.com" xlink:arcrole="homepage">


http://example.com/
</homepage>

Bạn cũng có thể gặp một số rắc rối ở bước 5. Bạn không thể sử dụng JSON-LD trên tài liệu XML nhưng

bạn có thể viết cấu hình ALPS. Nếu vẫn thất bại, bạn có thể quay lại hồ sơ mà con người có thể đọc

được dựa trên tài liệu API hiện có của bạn.

Nó có đáng không?

Mặc dù về mặt kỹ thuật có thể biến một API thiếu hiểu biết về siêu phương tiện thành một API siêu

đa phương tiện đầy đủ, nhưng lợi ích duy nhất bạn thu được từ việc thực hiện này có thể là cảm

giác hài lòng rực rỡ. Vấn đề là API cũ của bạn đã có ứng dụng khách. Đó là lý do tại sao bạn không

thể loại bỏ nó và thiết kế một API mới từ đầu. Bởi vì các máy khách hiện tại không có được sự linh

hoạt nhờ kiến thức về hypermedia nên sẽ rất khó khăn để di chuyển chúng sang API mới. Và tại sao

người dùng của bạn lại phải bận tâm tìm hiểu API mới?

Họ đã có sẵn kịch bản hoạt động được.

Nếu bạn vẫn dự định thay đổi API của mình thì việc trang bị thêm các cấu hình và điều khiển

hypermedia cho API đó là điều hợp lý để những thay đổi trong tương lai sẽ dễ dàng hơn. Nhưng việc

thêm siêu phương tiện vào API hiện có sẽ không giải quyết được bất kỳ vấn đề nào.

Cuộc phiêu lưu thứ hai của Alice

Trong Chương 1, tôi đã nói về một trang web sử dụng biển quảng cáo để quảng cáo URL tới trang chủ

của nó. Tôi kể câu chuyện về Alice, một nhân vật hư cấu đã gõ URL đó vào trình duyệt web của mình

và dần dần khám phá ra khả năng của trang web.

Câu chuyện khá buồn tẻ vì nó chỉ cho thấy World Wide Web hoạt động theo cách nó phải làm. Nhưng

bây giờ tôi có thể kể câu chuyện tương tự về một API không có gì chung với Web ngoại trừ giao thức

HTTP.

Giống như câu chuyện trước đây của tôi, câu chuyện này bắt đầu bằng một URL—URL biển quảng cáo cho một API:

https://www.example.com/

(Như bạn có thể thấy từ tên máy chủ, không giống như trang web ở Chương 1 và API ở Chương 2, API

này hoàn toàn là tưởng tượng.)

Tập 1: Đại diện vô nghĩa Đó là một đêm tối tăm và giông

bão. Máy khách HTTP thực hiện yêu cầu GET:

192 | Chương 9: Quy trình thiết kế


Machine Translated by Google

Máy chủ GET/


HTTP/1.1: www.example.com

Ai đó đang lái xe cho khách hàng này. Đó là Alice, nhân vật hư cấu ở Chương 1. Nhưng lần này cô ấy không sử

dụng trình duyệt web. Cô ấy đang sử dụng máy khách HTTP có thể lập trình để thăm dò khả năng của API mới.

Không có trình duyệt web để hiển thị các biểu diễn bằng đồ họa, Alice có thể gặp khó khăn trong việc hiểu

API này làm gì, nhưng cô ấy sẽ có thể tìm ra nó.

Máy chủ gửi lại một bản trình bày và Alice kiểm tra nó:

200 OK HTTP/1.1
Loại nội dung: application/vnd.myapi.qbit

===1 wkmje
<{data} {name:"qbe"} 1005>
<{link} {tab:"profile"} "https://www.example.com/The-Metric-System-And-You" >
<{link} {tab:"search"} "https://www.example.com/sosuy{?ebddt}">
===2 qmdk
<{link} {tab:"gyth"} "https:/ /www.example.com/click%20here%20for%20prizes">
<{data} {name:"ebddt"} "Zerde">
<{data} {name:"gioi"} "Snup">

"Cái quái gì đây?" Alice nói. “Nó không hẳn là XML và cũng không hẳn là JSON. Nó chứa đầy những chuỗi vô

nghĩa như qbe và URL dường như dẫn đến những đoạn phim mang tính giáo dục từ những năm 1970.”

Manh mối duy nhất của Alice là tiêu đề Content-Type , xác định định dạng dữ liệu có tên là application/

vnd.myapi.qbit. Không còn nơi nào khác để đi, Alice tra cứu application/vnd.myapi.qbit trong sổ đăng ký IANA

của các loại phương tiện. Điều này dẫn cô đến một trang web công ty mô tả định dạng dữ liệu không hẳn là

XML, không hẳn là JSON mà cô đang xem. Trang web đó cũng có một số thư viện mã để phân tích định dạng tệp.

Bằng cách sử dụng những công cụ này, cô ấy có thể mở rộng ứng dụng khách HTTP có thể lập trình của mình để

nó có thể biến luồng vô nghĩa thành cấu trúc dữ liệu hữu ích.

Bây giờ Alice đã biết một vài điều. Cô ấy biết rằng tài liệu này có hai phần, một
phần tên là wkmje và một phần tên là qmdk. Cô biết rằng tài liệu chứa ba bộ mô tả
ngữ nghĩa (gioi, ebddt và qbe) và ba điều khiển hypermedia (hai liên kết và Mẫu
URI). Vì một lý do kỳ lạ nào đó, loại phương tiện này đề cập đến mối quan hệ liên
kết dưới dạng “tab”, có nghĩa là ba điều khiển siêu phương tiện có hồ sơ quan hệ
liên kết , tìm kiếm và gyth.

Nhưng Alice không biết wkmje hay qmdk nghĩa là gì. Chúng là những từ vô nghĩa không được xác định cùng với

loại phương tiện. Một trong những điều khiển hypermedia trỏ đến https:// www.example.com/

click%20here%20for%20prizes, nhưng Alice không biết đầu bên kia là gì, vì URL trông giống như thư rác và mối

quan hệ liên kết (gyth) là chưa đăng ký với IANA.

Cuộc phiêu lưu thứ hai của Alice | 193


Machine Translated by Google

Alice biết rằng điều khiển tìm kiếm là Mẫu URI xác định một biến có tên là ebddt, nhưng cô ấy

không biết ebddt nghĩa là gì. Tìm kiếm quan hệ liên kết đã được đăng ký với IANA và việc đọc

định nghĩa giúp Alice tin tưởng rằng đây là một dạng tìm kiếm nào đó. Điều này có nghĩa là

ebddt có thể là một thuật ngữ tìm kiếm. Nó có thể liên quan đến bộ mô tả ngữ nghĩa được gọi là

ebddt, nhưng ebddt có nghĩa là gì?

Tập 2: Hồ sơ
Câu trả lời cho tất cả những câu hỏi này nằm ở liên kết đầu tiên của tài liệu:

<{link} {tab:"profile"} "https://www.example.com/The-Metric-System-And-You">

Đến thời điểm này, Alice đã đọc Chương 8 của cuốn sách này. Cô ấy biết rằng hồ sơ quan hệ liên

kết đã được đăng ký với IANA và nó chỉ ra một liên kết đến một tài liệu hồ sơ.

Cô ấy đưa ra yêu cầu thứ hai, hy vọng có được một tài liệu hồ sơ có thể hiểu được tất cả những
thứ ebddt và gyth này :

NHẬN /Máy chủ HTTP/1.1 của hệ thống số liệu-và-


bạn: www.example.com

Khi Alice đọc định nghĩa của application/vnd.myapi.qbit, cô nhận thấy rằng nó bao gồm các quy

tắc áp dụng hồ sơ ALPS cho một biểu diễn, vì vậy Alice đang hy vọng có một hồ sơ ALPS. Nhưng

ngay cả một trang web mà con người có thể đọc được cũng sẽ hữu ích.

Khi điều đó xảy ra, máy chủ sẽ gửi cho Alice một tài liệu ALPS:

HTTP/1.1 200 OK
Loại nội dung: application/vnd.amundsen.alps+xml

<alps version="1.0"> <doc>


Cơ sở

dữ liệu về các công thức nấu ăn có thể tìm kiếm

được. </doc>

<descriptor id="wkmje" type="semantic"> Thông tin


về toàn bộ cơ sở dữ liệu công thức nấu ăn. <descriptor
href="#qbe"> </descriptor>

<descriptor id="qmdk" type="semantic"> Thông


tin về công thức hiện đang được giới thiệu. <descriptor
href="#gyth"> <descriptor
href="#ebddt"> <descriptor
href="#gioi"> </descriptor>

<descriptor id="qbe" type="semantic"> Cho biết


tổng số công thức nấu ăn trong danh sách. </ mô tả>

<descriptor id="gyth" type="safe">

194 | Chương 9: Quy trình thiết kế


Machine Translated by Google

Một liên kết đến một


công thức. </ mô tả>

<descriptor id="ebddt" type="semantic">


Tên của một công thức nấu
ăn. </ mô tả>

<descriptor id="gioi" type="semantic"> Công thức


có đáp ứng các hạn chế về chế độ ăn uống khác nhau hay không. Giá trị "Snup" cho
biết công thức ăn chay. Giá trị "5a" cho biết công thức có chứa thịt. Cho phép các
giá trị khác (đối với không chứa gluten, kosher, v.v.), nhưng mọi giá trị khác
phải bắt đầu bằng tiền tố mở rộng "paq-". Nếu đưa ra hai giá trị trở lên thì
chúng phải được phân tách bằng ký tự SNOWMAN, ví dụ: "Snuppaq-vegan" </descriptor>

...

</alps>

Alice kết hợp hồ sơ ALPS với tài liệu vnd.myapi.qbit một cách tinh thần hoặc sử dụng
một công cụ tự động. Bây giờ tất cả có ý nghĩa. API này là cơ sở dữ liệu công thức
nấu ăn. Phần đầu tiên của phần trình bày mô tả toàn bộ cơ sở dữ liệu. Nó bao gồm cách
tìm kiếm theo tên công thức (ebddt) và tổng số công thức nấu ăn (qbe). Phần thứ hai
là liên kết đến một công thức đặc trưng (gyth). Nó đề cập đến tên công thức
(ebddt="Zerde") và thực tế đó là công thức chay (gioi="Snup").

Việc kết hợp tài liệu vnd.myapi.qbit với cấu hình ALPS trong một chương trình hiểu
được cả hai loại phương tiện có thể mang lại một GUI giống như Hình 9-12.

Hình 9-12. Có thể hiển thị GUI qbit bằng Cấu hình ALPS

Cuộc phiêu lưu thứ hai của Alice | 195


Machine Translated by Google

Điều này không hoàn hảo—các giải thích mà con người có thể đọc được không được viết để sử dụng trong GUI,

vì vậy GUI đọc một cách vụng về—nhưng nó tốt hơn rất nhiều so với tài liệu vnd.myapi.qbit khó hiểu của

chính nó .

Là một lập trình viên, Alice có thể sử dụng hồ sơ ALPS để triển khai bất kỳ loại máy khách nào mà tôi đã

mô tả trong Hình 5-3. Dưới đây là một số ví dụ:

• Một ứng dụng khách do con người điều khiển để tìm kiếm cơ sở dữ liệu

công thức nấu ăn. • Trình thu thập thông tin tải xuống tất cả các

công thức nấu ăn mà nó có thể tìm thấy. • Một công cụ giám sát định kỳ thực hiện tìm

kiếm các công thức nấu ăn chay mới. • Một đại lý lấy danh sách các thành phần có trong tay và lên kế

hoạch cho bữa ăn. Tác nhân sử dụng API công thức để tìm các công thức sử dụng nguyên liệu có sẵn. Nó

cũng tích hợp với API định giá của cửa hàng tạp hóa để tra cứu giá thành của những nguyên liệu còn

thiếu. Đầu ra của nó là danh sách các công thức nấu ăn sử dụng hầu hết các nguyên liệu sẵn có và có
chi phí bổ sung tối thiểu.

Nhưng thực tế, Alice không hề quan tâm đến việc nấu nướng. Sau khi hiểu được ý nghĩa của tài liệu mà cô

ấy được cung cấp ban đầu, cô ấy sẽ ngừng sử dụng API kỳ lạ này và không bao giờ quay lại.

Alice đã tìm ra điều đó Khi

tôi thiết kế API này, tôi đã thực hiện mọi bước có thể để che giấu mục đích của nó. Tôi đã tạo một loại

phương tiện khó hiểu, application/vnd.myapi.qbit. Tôi đã sử dụng tab thuật ngữ vô nghĩa để gắn nhãn các

mối quan hệ liên kết, thay vì thuật ngữ tiêu chuẩn rel. Tôi đã cung cấp các URL có tên dẫn đầu sai. Tôi

đã sử dụng các chuỗi ký tự ngẫu nhiên để đặt tên cho các bộ mô tả ngữ nghĩa và các mối quan hệ liên kết.

Tôi đã phát minh ra những quy tắc tùy tiện, lố bịch để xác định liệu một công thức nấu ăn có đáp ứng các

hạn chế về chế độ ăn uống khác nhau hay không. Văn bản hữu ích duy nhất mà con người có thể đọc được

trong tài liệu vnd.mya pi.qbit là “Zerde”, tên của công thức đặc trưng.6 Và không có tài liệu API như

người ta thường hiểu: chỉ là một URL biển quảng cáo.

Bất chấp tất cả những điều này, Alice vẫn có thể tìm ra cách hoạt động của API, bởi vì ngay cả trong cơn

bạo dâm của mình, tôi vẫn tuân theo các quy tắc tôi đã đặt ra trong cuốn sách này. Tôi đã cung cấp tiêu

đề Kiểu nội dung chứa loại phương tiện có định dạng trình bày khó hiểu. Alice đã có thể tra cứu nó trong

sổ đăng ký IANA và đọc phần giải thích chính thức về định dạng. Trong tài liệu vnd.myapi.qbit , tôi đã sử

dụng mối quan hệ liên kết (tìm kiếm) đã đăng ký IANA để mô tả một biểu mẫu tìm kiếm và một (hồ sơ) khác

để liên kết đến một tài liệu hồ sơ. Tài liệu hồ sơ có thể đọc được bằng máy nhưng nó cũng chứa các thông
tin cần thiết mà con người có thể đọc được.

6. Zerde là món tráng miệng của Thổ Nhĩ Kỳ, một loại bánh gạo. Tôi chọn nó vì nghĩ rằng không có nhiều độc giả của tôi sẽ
nhận ra từ đó.

196 | Chương 9: Quy trình thiết kế


Machine Translated by Google

câu hỏi về ý nghĩa của sự đại diện . Sau khi tìm thấy và đọc thông tin đó, Alice đã hiểu ngữ
nghĩa của ứng dụng và biết rằng cô ấy không muốn sử dụng API.

Rõ ràng là bạn không nên cố gắng gây khó khăn cho người dùng của mình. Bạn không nên cung cấp
các URL vô nghĩa hoặc tạo ngẫu nhiên tên các mối quan hệ liên kết của mình.7 Điểm mấu chốt
của câu chuyện này là đó không phải là vấn đề ở cấp độ kỹ thuật. Bạn cần đảm bảo rằng giao
thức API và ngữ nghĩa ứng dụng của bạn được ghi lại, thông qua sự kết hợp của các cấu hình
và định nghĩa loại phương tiện. Bạn cần coi tài liệu của mình không phải là một sản phẩm
riêng biệt mà là một phần hạng nhất của API, như một bản trình bày được liên kết với các bản
trình bày khác bằng cách sử dụng điều khiển siêu phương tiện và mối quan hệ liên kết.

Trong phần trình bày API của bạn, các mối quan hệ liên kết và URL mà con người có thể đọc

được là những gợi ý hữu ích—các cách viết tắt giúp các nhà phát triển ứng dụng khách không
phải liên tục tra cứu ebddt trong tài liệu của bạn. Bản thân chúng không phải là tài liệu.
Tài liệu được nhúng trong API của bạn. Đó là điều cho phép API của bạn thay đổi theo thời gian.

7. Trừ khi bạn muốn chắc chắn rằng họ viết các ứng dụng khách có khả năng nhận biết siêu phương tiện.

Cuộc phiêu lưu thứ hai của Alice | 197


Machine Translated by Google
Machine Translated by Google

CHƯƠNG 10

Sở thú Hypermedia

Có rất nhiều định dạng tài liệu hypermedia đang được sử dụng. Một số được thiết kế cho những mục

đích rất chuyên biệt—những người sử dụng chúng thậm chí có thể không coi chúng là định dạng siêu

phương tiện. Các định dạng hypermedia khác được sử dụng phổ biến đến mức mọi người không thực sự

nghĩ đến chúng. Trong chương này, tôi sẽ đưa bạn đi tham quan một “vườn thú” chứa các định dạng

hypermedia phổ biến nhất và thú vị nhất.

Tôi sẽ không đi sâu vào chi tiết kỹ thuật. Bất kỳ định dạng nào trong số này đều có thể không phải

là định dạng bạn muốn sử dụng và tôi đã đề cập đến nhiều định dạng đó trước đó trong cuốn sách.

Nhiều định dạng vẫn đang được phát triển tích cực và chi tiết của chúng có thể thay đổi. Nếu bạn

quan tâm đến một trong những mẫu vật của vườn thú, bước tiếp theo là đọc thông số kỹ thuật chính thức của nó.

Mục tiêu của tôi là giúp bạn hiểu được nhiều dạng hypermedia có thể thực hiện và cho thấy chúng tôi

đã giải quyết các vấn đề cơ bản về việc biểu diễn nó bao nhiêu lần. Sở thú hypermedia đã đầy đến

mức bạn có thể không cần xác định loại phương tiện hoàn toàn mới cho API của mình. Bạn sẽ có thể

chọn loại phương tiện hiện có và viết hồ sơ cho nó.

Tôi đã tổ chức vườn thú hypermedia theo hướng giới thiệu của tôi về hypermedia.

Có một phần dành cho các định dạng dành riêng cho miền (a la Chương 5), một phần dành cho các định

dạng có mục đích chính là triển khai mẫu bộ sưu tập (a la Chương 6) và một phần dành cho các định

dạng hypermedia chung (a la Chương 7).

Đối với các định dạng như Bộ sưu tập+JSON mà tôi đã trình bày chi tiết, tôi sẽ tóm tắt ngắn gọn về

định dạng và hướng bạn đến cuộc thảo luận trước đó. Có một số định dạng siêu phương tiện mà tôi sẽ

không thảo luận trong chương này, vì chúng có những cách tiếp cận khác với REST so với cách tôi đã
ủng hộ cho đến nay trong cuốn sách này. Tôi sẽ đề cập đến RDF và các hậu duệ của nó trong Chương 12

và Định dạng liên kết cốt lõi trong Chương 13.

199
Machine Translated by Google

Định dạng dành riêng cho tên miền

Các loại phương tiện này được thiết kế để thể hiện các vấn đề trong một miền cụ thể. Mỗi định nghĩa

một số ngữ nghĩa ứng dụng rất cụ thể và mặc dù bạn có thể sử dụng chúng để truyền đạt các ngữ nghĩa

khác nhau nhưng đó có thể là một ý tưởng tồi.

Mê cung+XML

• Loại phương tiện: application/vnd.amundsen.maze+xml • Định

nghĩa trong: tiêu chuẩn cá nhân

• Phương tiện: XML

• Ngữ nghĩa giao thức: điều hướng bằng liên kết GET • Ngữ

nghĩa ứng dụng: trò chơi mê cung • Được đề

cập trong: Chương 5

Mê cung+XML xác định các thẻ XML và các mối quan hệ liên kết liên quan đến mê cung, các ô trong mê

cung và các kết nối giữa các ô. Hình 10-1 đưa ra sơ đồ trạng thái của ngữ nghĩa giao thức của nó.

Hình 10-1. Ngữ nghĩa giao thức của Mê cung+XML

Mê cung+XML xác định thẻ <link> có quan hệ liên kết và xác định chuyển đổi trạng thái an toàn; nghĩa

là nó cho phép khách hàng thực hiện yêu cầu GET. Bạn có thể mở rộng Mê cung+XML bằng cách đưa vào

các quan hệ liên kết tùy chỉnh hoặc bằng cách xác định các thẻ XML bổ sung. Vì đây là định dạng XML

nên bạn cũng có thể sử dụng XForms (qv) để thể hiện các chuyển đổi trạng thái không an toàn.

Tôi thực sự không khuyên bạn nên sử dụng Mê cung+XML, ngay cả khi bạn tình cờ tạo một trò chơi mê

cung. Đây chỉ là một ví dụ và tôi đặt nó lên hàng đầu để làm ví dụ về cách tôi đánh giá các định

dạng hypermedia.

200 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

Tìm kiếm mở

• Loại phương tiện: application/opensearchdescription+xml (đang chờ đăng ký) • Được xác định trong:

tiêu chuẩn liên minh

• Phương tiện: XML

• Ngữ nghĩa giao thức: tìm kiếm bằng GET • Ngữ nghĩa

ứng dụng: truy vấn tìm kiếm • Được đề cập trong:

Chương 6

OpenSearch là một tiêu chuẩn để thể hiện các hình thức tìm kiếm. Nó có thể được sử dụng độc lập hoặc được

tích hợp vào một API khác bằng cách sử dụng mối quan hệ liên kết tìm kiếm . Sơ đồ trạng thái của nó trông
như thế này:

Đây là một đại diện OpenSearch đơn giản. Đích của biểu mẫu OpenSearch ( thuộc tính mẫu của thẻ <Url> của

nó ) là một chuỗi tương tự như Mẫu URI (RFC 6570), mặc dù nó không có tất cả các tính năng của Mẫu URI:

<?xml version="1.0" Encoding="UTF-8"?>


<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"> <ShortName>Tìm
kiếm tên</ShortName> < Mô tả>Tìm kiếm cơ
sở dữ liệu theo tên</Description> <Url type="application/atom+xml"
rel="results"
template="http://example.com/search?q={searchTerms}"/>
</OpenSearchDescription>

OpenSearch không xác định cách thể hiện kết quả tìm kiếm. Bạn nên sử dụng bất kỳ định dạng danh sách nào

phù hợp với định dạng trình bày chính của mình.

Tài liệu chi tiết vấn đề

• Loại phương tiện: application/api-problem+json • Được mô

tả trong: Internet-Draft “draft-nottingham-http-problem” • Phương tiện: JSON (với

các quy tắc để tự động chuyển đổi sang XML) • Ngữ nghĩa giao thức: điều hướng bằng

GET

Định dạng dành riêng cho tên miền | 201


Machine Translated by Google

• Ngữ nghĩa ứng dụng: báo cáo lỗi

Tài liệu chi tiết về sự cố mô tả tình trạng lỗi. Nó sử dụng văn bản có cấu trúc, con người có thể

đọc được để thêm ngữ nghĩa tùy chỉnh vào mã trạng thái của HTTP. Đó là định dạng JSON đơn giản được

thiết kế để thay thế bất kỳ định dạng dùng một lần nào mà bạn đang nghĩ đến việc thiết kế để truyền

tải thông báo lỗi của mình.

Giống như hầu hết các tài liệu hypermedia dựa trên JSON, chi tiết vấn đề có dạng đối tượng JSON. Đây

là tài liệu có thể được cung cấp cùng với mã trạng thái HTTP 503 (Dịch vụ không khả dụng):

{ "describeBy": "http://example.com/scheduled-maintenance", "supportId":


"http://example.com/maintenance/outages/20130533", "httpStatus" : 503 "title":
"The API ngừng hoạt
động để bảo trì theo lịch.", "detail": "Việc ngừng hoạt động này sẽ
kéo dài từ 02:00 đến 04:30 UTC." }

Hai trong số các thuộc tính này được định nghĩa là các liên kết hypermedia. Thuộc tính được mô tảBy là một

liên kết đến phần giải thích mà con người có thể đọc được về cách biểu diễn.1

Thuộc tính supportId là một URL đại diện cho trường hợp cụ thể này của sự cố.

Không có kỳ vọng rằng người dùng cuối sẽ tìm thấy bất cứ điều gì ở đầu kia của URL này.

Đó có thể là một URL nội bộ để nhân viên hỗ trợ API sử dụng hoặc có thể là một URI, một ID duy nhất

không trỏ đến bất cứ điều gì cụ thể.

Các thuộc tính descriptionBy và title là bắt buộc; phần còn lại là tùy chọn. Bạn cũng có thể thêm

các thuộc tính bổ sung cụ thể cho API của mình.

SVG

• Loại phương tiện: hình ảnh/svg+xml

• Phương tiện: XML

• Ngữ nghĩa giao thức: giống XLink

• Ngữ nghĩa ứng dụng: đồ họa vector

SVG là một định dạng hình ảnh. Không giống như JPEG, đại diện cho hình ảnh ở cấp độ pixel, hình ảnh

SVG được tạo thành từ các hình dạng. SVG bao gồm một điều khiển siêu phương tiện cho phép các phần

khác nhau của hình ảnh liên kết với các tài nguyên khác nhau.

1. được mô tảBy là mối quan hệ liên kết đã đăng ký IANA, là phiên bản tổng quát hơn của hồ sơ. Một tài nguyên

được mô tả Bởi bất kỳ tài nguyên nào làm sáng tỏ cách giải thích của nó.

202 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

Điều khiển hypermedia đó là thẻ <a> có chức năng tương tự như thẻ <a> của HTML .
Đây là biểu diễn SVG đơn giản của một ô trong mê cung của Chương 5:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg"


xmlns:xlink="http://www.w3.org/1999/xlink">

<orth x="100" y="80" width="100" Height="50" Stroke="black" fill="white"/> <text x="105"


y="105" font-size= "10">Sảnh kinh hoàng</text>

<a xlink:href="/cells/I" xlink:arcrole="http://alps.io/example/maze#north"> <line x1="150"


y1="80" x2="150" y2 ="40" đột quỵ="black"/> <text x="130" y="38"
font-size="10">Tiến về phía Bắc!</text> </a>

<a xlink:href="/cells/O" xlink:arcrole="http://alps.io/example/maze#east">


<line x1="200" y1="105" x2="240" y2="105" Stroke="black"/> <text
x="240" y="107" font-size="10">Đi Đông!</text> </a>

<a xlink:href="/cells/M" xlink:arcrole="http://alps.io/example/maze#west">


<line x1="100" y1="105" x2="60" y2="105" Stroke="black"/> <text
x="18" y="107" font-size="10">Đi Tây!</text> </a>

</svg>

Hình 10-2 cho thấy cách máy khách có thể hiển thị tài liệu này.

Hình 10-2. Biểu diễn SVG của một ô mê cung

SVG là một giải pháp thay thế tốt cho HTML để xây dựng các ứng dụng di động. SVG cũng có thể

được kết hợp với HTML 5: chỉ cần dán thẻ <svg> vào đánh dấu HTML để có được hình ảnh SVG nội

tuyến.

Thẻ <a> của SVG không thực sự xác định bất kỳ khả năng siêu phương tiện nào. Nó chỉ là một thẻ

giữ chỗ cho vai trò của XLink và các thuộc tính href (qv). Vì SVG là định dạng XML nên bạn cũng

có thể thêm biểu mẫu XForms (qv) vào SVG và nhận được ngữ nghĩa giao thức tương đương với HTML.

Điều này không hữu ích bằng việc nhúng SVG vào HTML vì nó yêu cầu máy khách hiểu cả SVG và
XForms.

Định dạng dành riêng cho tên miền | 203


Machine Translated by Google

Giọng nóiXML

• Loại phương tiện: application/voicexml+xml •

Được xác định trong: Tiêu chuẩn mở W3C, với phần mở rộng

• Phương tiện: XML

• Ngữ nghĩa giao thức: GET để điều hướng; chuyển đổi trạng thái tùy ý thông qua các hình thức:
GET cho quá trình chuyển đổi an toàn, POST cho quá trình chuyển đổi không an toàn

• Ngữ nghĩa ứng dụng: hội thoại bằng giọng nói

Trong Chương 5, tôi đã đưa ra sự tương tự giữa một máy khách HTTP điều hướng API hypermedia và

một con người đang điều hướng cây điện thoại. Chà, rất nhiều cây điện thoại thực sự được triển

khai trên phần phụ trợ dưới dạng API hypermedia. Định dạng trình bày họ sử dụng là VoiceXML.

Đây là một cách trình bày VoiceXML có thể có của một ô trong trò chơi mê cung của Chương 5:

<?xml version="1.0" mã hóa="UTF-8"?> <vxml


xmlns="http://www.w3.org/2001/vxml" xmlns:xsi="http://
www.w3.org /2001/XMLSchema-instance" xsi:schemaLocation="http://
www.w3.org/2001/vxml http://www.w3.org/TR/voicexml20/vxml.xsd"
version="2.1">

<thực đơn>

<lời nhắc>
Bạn đang ở trong Sảnh Kinh hoàng. Các lối thoát là: <enumerate/> </prompt>

<choice next="/cells/I">
Miền

Bắc </choice>

<choice next="/cells/M">
Phía đông

</lựa chọn>

<choice next="/cells/O">
Tây

</ lựa chọn>

<noinput>Hãy nói một trong <enumerate/></noinput> <nomatch>Bạn


không thể đi theo hướng đó. Các lối thoát là: <enumerate/></nomatch> </menu> </
vxml>

Nếu bạn đang chơi trò chơi mê cung trên điện thoại, bạn sẽ không bao giờ nhìn thấy trực tiếp biểu

tượng này. “Trình duyệt” VoiceXML nằm ở đầu bên kia của đường dây điện thoại. Khi nhận được thông

báo này, nó sẽ xử lý tài liệu bằng cách đọc to <lời nhắc> cho bạn: “Bạn đang ở trong Phòng giải

trí kinh hoàng. Các lối ra là: bắc, đông, tây.”

204 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

Mỗi thẻ <choice> là một liên kết hypermedia. Trình duyệt chờ bạn kích hoạt một liên kết bằng
cách nói điều gì đó. Nó sử dụng nhận dạng giọng nói để tìm ra liên kết nào bạn đang kích hoạt.
Có một bước xác thực: nếu bạn không nói gì hoặc nói điều gì đó không ánh xạ tới một trong các

liên kết, trình duyệt sẽ đọc cho bạn một thông báo lỗi ( <noinput> hoặc <no match>) và chờ

nhập lại.

Khi bạn quản lý để kích hoạt một liên kết, trình duyệt sẽ thực hiện yêu cầu NHẬN tới URL được

đề cập trong thuộc tính tiếp theo tương ứng . Máy chủ phản hồi bằng một biểu diễn VoiceXML
mới và trình duyệt xử lý biểu diễn đó và cho bạn biết hiện tại bạn đang ở trong ô mê cung nào.

Thẻ <menu> chỉ là cách điều khiển siêu phương tiện đơn giản nhất của VoiceXML. Ngoài ra còn

có thẻ <form> sử dụng ngữ pháp nhận dạng giọng nói để thực hiện yêu cầu GET hoặc POST dựa
trên nội dung bạn yêu cầu. Đây là biểu mẫu VoiceXML để bật các công tắc bí ẩn mà tôi đã xác
định ở Chương 7:

<form id="switches">
<grammar src="command.grxml" type="application/srgs+xml"/>

<tên ban đầu="bắt đầu">


<nhắc> Ở
đây có một công tắc đỏ và một công tắc xanh. Công tắc đỏ ở trên và công tắc
xanh ở dưới.

Bạn thích làm gì? </prompt> </


ban đầu>

<tên trường="lệnh">
<prompt>
Bạn muốn bật công tắc đỏ, bật công tắc xanh hay quên nó đi? </prompt> </field>

<tên trường="chuyển đổi">

<prompt>
Nói tên của công tắc. </
prompt> </
field>

<đầy>

<submit next="/cells/I" Method="POST" namelist="command switch"/> </filled> </


form>

Thẻ <grammar> là một liên kết nội tuyến tương tự như thẻ HTML <img> hoặc <script> . Nó tự
động nhập một tài liệu được viết theo định dạng do W3C's Speech quy định

Định dạng dành riêng cho tên miền | 205


Machine Translated by Google

Đặc tả ngữ pháp công nhận.2 Tôi sẽ không hiển thị tệp SRGS ở đây vì SRGS không phải là định
dạng hypermedia. Đủ để nói rằng khi bạn nói những từ “bật công tắc đỏ” hoặc “quên nó đi”, ngữ
pháp SRGS là thứ cho phép trình duyệt VoiceXML chuyển đổi những từ đó thành một tập hợp các

cặp khóa-giá trị khớp với biểu mẫu. lệnh và chuyển đổi trường :

lệnh=công tắc
lật=công tắc đỏ

Sau khi các trường được điền các giá trị thu được thông qua nhận dạng giọng nói, thẻ <sub

mit> sẽ cho trình duyệt VoiceXML biết cách định dạng yêu cầu HTTP POST. Nó trông giống như
việc gửi biểu mẫu HTML:

POST /cells/I HTTP/1.1


Loại nội dung: application/x-www-form-urlencoded

command=flip&switch=red%20switch

Một tài liệu VoiceXML không khác gì mã ngôn ngữ lập trình.
VoiceXML sử dụng các thành ngữ trong lập trình để thể hiện luồng hội thoại thông qua cây hộp

thoại: <goto> để chuyển từ phần này sang phần khác của hộp thoại, <if> để thể hiện một điều

kiện và thậm chí <var> để gán giá trị cho một biến .

Định dạng mẫu bộ sưu tập

Ba tiêu chuẩn trong phần này có ngữ nghĩa giao thức và ứng dụng tương tự nhau, bởi vì chúng

đều triển khai mẫu bộ sưu tập mà tôi đã trình bày trong Chương 6. Trong mẫu bộ sưu tập, một
số tài nguyên nhất định được chỉ định là tài nguyên “item”. Một mục thường phản hồi GET, PUT
và DELETE và cách biểu diễn của nó tập trung vào việc biểu diễn các bit dữ liệu có cấu trúc.
Các tài nguyên khác được chỉ định là tài nguyên "bộ sưu tập". Một bộ sưu tập thường phản hồi
GET và POST-to-append, và cách trình bày của nó tập trung vào việc liên kết đến mục
tài nguyên.

Ba tiêu chuẩn này có những cách tiếp cận khác nhau đối với mẫu bộ sưu tập; họ có thể không sử
dụng thuật ngữ “bộ sưu tập” hoặc “vật phẩm”, nhưng tất cả đều thực hiện khá giống nhau.

Bộ sưu tập+JSON

• Loại phương tiện: application/vnd.amundsen.collection+json • Được

xác định trong: tiêu chuẩn cá nhân

• Phương tiện: JSON

2. Được xác định ở đây.

206 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

• Ngữ nghĩa giao thức: mẫu thu thập (GET/POST/PUT/DELETE), cộng với tìm kiếm‐

ing (sử dụng GET)

• Ngữ nghĩa ứng dụng: mẫu bộ sưu tập (“bộ sưu tập” và “mục”) • Được đề cập trong:

Chương 6

Collection+JSON được thiết kế như một giải pháp thay thế dựa trên JSON đơn giản cho Giao thức xuất bản

Atom (qv). Đây là phiên bản chính thức, có khả năng nhận biết siêu phương tiện của các nhà phát triển

API có xu hướng thiết kế lần đầu tiên thông qua quy trình. Hình 10-3 cho thấy ngữ nghĩa giao thức của
nó.

Hình 10-3. Ngữ nghĩa giao thức của Collection+JSON

Giao thức xuất bản Atom


• Loại phương tiện: ứng dụng/atom+xml, ứng dụng/atomsvc+xml và ứng dụng/atomcat+xml

• Được định nghĩa trong: RFC 5023 và RFC 4287

• Phương tiện: XML

• Ngữ nghĩa giao thức: mẫu thu thập (GET/POST/PUT/DELETE); các tiện ích mở rộng được xác định rõ

ràng thêm tính năng tìm kiếm và các hình thức điều hướng khác, tất cả đều sử dụng liên kết hoặc
biểu mẫu GET

• Ngữ nghĩa ứng dụng: mẫu thu thập (nguồn cấp dữ liệu và mục nhập); các mục có ngữ nghĩa của các

bài đăng trên blog (tác giả, tiêu đề, danh mục, v.v.); một mục nhập không phải là tài liệu Atom

(ví dụ: đồ họa nhị phân) được chia thành Mục nhập phương tiện nhị phân và Mục nhập Atom chứa siêu

dữ liệu • Được đề cập trong: Chương

Định dạng mẫu bộ sưu tập | 207


Machine Translated by Google

Tiêu chuẩn API ban đầu, AtomPub đã đi tiên phong trong mẫu bộ sưu tập và cách tiếp cận RESTful đối

với API nói chung. Là một tiêu chuẩn dựa trên XML trong một lĩnh vực hiện bị thống trị bởi các biểu

diễn JSON, AtomPub giờ đây trông hơi lỗi thời, nhưng nó đã truyền cảm hứng cho một số tiêu chuẩn và

mối quan hệ liên kết khác có thể được sử dụng với các định dạng siêu phương tiện khác. Hình 10-4 cho

thấy ngữ nghĩa giao thức của nó.

Hình 10-4. Ngữ nghĩa giao thức của AtomPub

Mặc dù ngữ nghĩa ứng dụng của Atom ngụ ý rằng nó chỉ nên được sử dụng cho các ứng dụng cấp tin tức

như viết blog và quản lý nội dung API, nhưng tiêu chuẩn này rất có khả năng mở rộng. Có lẽ tiện ích

mở rộng đáng chú ý nhất là Giao thức dữ liệu của Google, nền tảng nền tảng API của Google. Google

thêm các thẻ dành riêng cho tên miền vào AtomPub để mô tả ngữ nghĩa ứng dụng của từng trang web của

mình. Nguồn cấp dữ liệu Atom trở thành tập hợp các video (API YouTube) hoặc tập hợp các ô bảng tính

(Bảng tính Google).

Nếu bạn cho rằng ngữ nghĩa ứng dụng của mình không phù hợp với mẫu bộ sưu tập, hãy xem thư mục API

của Google có thể thuyết phục bạn bằng cách khác. Giao thức dữ liệu của Google cũng xác định JSON

tương đương với các biểu diễn XML của AtomPub, mặc dù đây là tiêu chuẩn tiền pháp định chứ không phải

thứ bạn được mời sử dụng lại.

Một số tiêu chuẩn mở xác định các tiện ích mở rộng AtomPub, bao gồm Tiện ích mở rộng luồng Atom và

phần tử mục nhập đã xóa . Tôi đã trình bày những điều này ở Chương 6.

OData

• Loại phương tiện: application/json;odata=fullmetadata • Được xác

định trong: tiêu chuẩn mở đang được tiến hành •

Phương tiện: JSON cho một số phần, XML cho một số phần khác

208 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

• Ngữ nghĩa giao thức: mẫu thu thập được sửa đổi (GET/POST/PUT/DELETE) với

PATCH để cập nhật một phần và GET cho các truy vấn; chuyển đổi trạng thái tùy ý với các
biểu mẫu (GET cho chuyển đổi an toàn và POST cho chuyển đổi không an toàn)

• Ngữ nghĩa ứng dụng: mẫu thu thập (nguồn cấp dữ liệu và mục nhập)

Ngữ nghĩa của OData được lấy cảm hứng rất nhiều từ Giao thức xuất bản Atom. Trên thực tế, API
OData có thể cung cấp các biểu diễn Atom và khách hàng có thể coi API OData là API AtomPub với

rất nhiều tiện ích mở rộng. Nhưng tôi sẽ coi OData là một API phục vụ hầu hết các biểu diễn
JSON.

Hình 10-5 hiển thị khung nhìn về ngữ nghĩa giao thức của OData, được đơn giản hóa để chỉ hiển
thị các phần của OData mà tôi sẽ trình bày ở đây. Và đây là bản trình bày OData của một bộ sưu
tập từ API tiểu blog, tương tự như You Type It, We Post It của Chương 2:

{
"odata.metadata":
"http://api.example.com/YouTypeItWePostIt.svc/$metadata#Posts", "value": [ {

"Nội dung": "Đây là bài đăng thứ hai.", "Id":


2,
"PostedAt": "2013-04-30T03:34:12.0992416-05:00",
"PostedAt@odata.type": "Edm. DateTimeOffset",
"PostedBy@odata.navigationLinkUrl": "Bài viết(2)/PostedBy",
"odata.editLink": "Bài viết(2)",
"odata.id": "http://api.example.com/ YouTypeItWePostIt.svc/Posts(2)", "odata.type":
"YouTypeItWePostIt.Post" }, {

"Nội dung": "Đây là bài đăng đầu tiên",


"Id": 1,
"PostedAt": "2013-04-30T04:14:53.0992416-05:00",
"PostedAt@odata.type": "Edm.DateTimeOffset ",
"PostedBy@odata.navigationLinkUrl": "Bài viết(1)/PostedBy",
"odata.editLink": "Bài viết(1)",
"odata.id": "http://api.example.com/YouTypeItWePostIt .svc/Posts(1)", "odata.type":
"YouTypeItWePostIt.Post" },

"#Posts.RandomPostForDate":
{ "title": "Nhận một bài đăng ngẫu nhiên cho ngày nhất
định", "target": "Posts/RandomPostForDate" }

Định dạng mẫu bộ sưu tập | 209


Machine Translated by Google

Hình 10-5. Ngữ nghĩa giao thức của OData (được đơn giản hóa)

Giống như các định dạng dựa trên JSON khác mà chúng ta đã thấy, biểu diễn OData là các đối tượng JSON có

thuộc tính được đặt tên bằng các chuỗi ngắn, bí ẩn. Thuộc tính như Content hoặc PostedAt là dữ liệu JSON

thông thường và tên của nó đóng vai trò như một bộ mô tả ngữ nghĩa. Thuộc tính có tên bao gồm odata. tiền

tố là điều khiển hypermedia hoặc một số siêu dữ liệu dành riêng cho OData. Một số ví dụ từ tài liệu này:

• Thuộc tính odata.id chứa một ID duy nhất—nghĩa là một URI—cho một

tài nguyên loại mục nhập.

• Thuộc tính PostedAt@odata.type chứa thông tin loại ngữ nghĩa cho giá trị của thuộc tính PostedAt .

Loại, Edm.DateTimeOffset, đề cập đến định dạng lược đồ của OData: Mô hình Dữ liệu Thực thể. • Thuộc

tính odata.editLink hoạt động giống như một

liên kết AtomPub với rel="edit". Nếu bạn muốn sửa đổi hoặc xóa một trong các bài đăng mẫu, bạn có thể

gửi yêu cầu PUT, PATCH hoặc DELETE tới URL tương đối Bài đăng(2) hoặc Bài đăng(1).

• Thuộc tính PostedBy@odata.navigationLinkUrl chứa liên kết hypermedia tới một tài nguyên khác. Phần

dành riêng cho ứng dụng của tên thuộc tính, PostedBy, đóng vai trò là mối quan hệ liên kết. Về mặt

con người, đây là một liên kết đến người dùng đã xuất bản bài đăng cụ thể này.

Ngữ nghĩa giao thức của tài nguyên OData lặp lại những gì bạn đã thấy trong Collection+JSON và AtomPub.

Tài nguyên bộ sưu tập hỗ trợ GET (để lấy phần trình bày) và POST (để thêm một mục mới vào bộ sưu tập).

Các tài nguyên loại mục nhập hỗ trợ GET, cũng như PUT, DELETE và PATCH (thông qua odata.editLink của

chúng) .

Lọc OData

cũng xác định một tập hợp ngữ nghĩa giao thức ngầm để lọc và sắp xếp một bộ sưu tập, sử dụng ngôn ngữ

truy vấn tương tự như SQL. Nếu bạn biết mình có URL tới bộ sưu tập OData, bạn có thể thao tác URL đó theo

nhiều cách khác nhau. Gửi NHẬN

210 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

đối với các URL kết quả sẽ mang lại các biểu diễn lọc và phân trang bộ sưu tập theo nhiều cách

khác nhau.

Tôi nói rằng các ngữ nghĩa giao thức này là tiềm ẩn vì bạn không cần phải tìm kiếm một biểu mẫu

siêu phương tiện cho bạn biết cách thực hiện yêu cầu HTTP để thực hiện một tìm kiếm cụ thể. Bạn
có thể xây dựng yêu cầu đó dựa trên các quy tắc có trong thông số OData.

Hãy xem xét một vài ví dụ. Giả sử URL cơ sở (tương đối) của bộ sưu tập microblog là /Bài viết.

Bạn không cần biểu mẫu hypermedia để cho bạn biết cách tìm kiếm các bài đăng trên blog bao gồm

chuỗi “thứ hai” trong thuộc tính Nội dung của chúng . Bạn có thể tự xây dựng URL3 :

/Posts$filter=substringof('giây', Nội dung)

Bạn có thể tìm kiếm các bài đăng bao gồm “thứ hai” trong Nội dung của họ và được Đăng bởi một

tài nguyên có thuộc tính Tên người dùng là “alice”:

/Posts$filter=substringof('second', Content)+ và +PostedBy/Tên người dùng eq 'alice')

Bạn chỉ có thể chọn năm bài đăng cuối cùng được xuất bản trong năm 2012:

/Posts$filter=year(PostedAt) eq 2012&$top=5

Bạn muốn có được trang thứ hai của danh sách đó? Bạn không cần phải tìm liên kết với mối quan

hệ tiếp theo trong biểu diễn. URL bạn nên sử dụng được xác định bởi thông số OData:

/Posts$filter=year(PostedAt) eq 2012&$top=5&skip=5

Theo mặc định, bộ sưu tập microblog trình bày các mục theo thứ tự thời gian đảo ngược dựa trên

giá trị của thuộc tính PostedAt . Thay vào đó, nếu bạn muốn sử dụng thứ tự thời gian, thông số

OData sẽ giải thích URL bạn nên sử dụng:

/Posts$orderBy=Đã đăngTại tăng dần

Trong các tiêu chuẩn mẫu bộ sưu tập khác, máy chủ phải cung cấp điều khiển siêu phương tiện để

mô tả rõ ràng từng nhóm tìm kiếm được phép. Collection+JSON phục vụ các mẫu tìm kiếm, AtomPub
phục vụ các biểu mẫu OpenSearch. Bộ sưu tập OData không cần cung cấp thông tin này vì mọi bộ

sưu tập OData đều hỗ trợ ngầm toàn bộ giao thức truy vấn OData. Khách hàng không cần biểu mẫu

hypermedia để biết có thể gửi yêu cầu GET tới một số URL nhất định hay không. Bản thân định
dạng OData đặt ra các ràng buộc bổ sung trên máy chủ để đảm bảo rằng một số URL nhất định sẽ

hoạt động.

OData xác định thêm một vài bit ngữ nghĩa giao thức ngầm, chủ yếu liên quan đến mối quan hệ

giữa các tài nguyên. Tôi sẽ không trình bày chúng ở đây.

Chức năng và tài liệu siêu dữ liệu

Ngoài tập hợp các chuyển đổi trạng thái ấn tượng được xác định ngầm định bởi giao thức truy vấn

của OData, một biểu diễn OData có thể bao gồm các điều khiển siêu phương tiện rõ ràng mô tả

3. Rõ ràng tất cả các URL này cần phải được mã hóa URL. Tôi đã để chúng không được mã hóa để cho rõ ràng.

Định dạng mẫu bộ sưu tập | 211


Machine Translated by Google

bất kỳ sự chuyển đổi trạng thái nào cả. Các điều khiển này có ngữ nghĩa giao thức tương tự như các dạng

HTML. Quá trình chuyển đổi an toàn được gọi là “hàm” và chúng sử dụng HTTP GET. Các chuyển đổi không an

toàn được gọi là “hành động” và chúng sử dụng HTTP POST. Tôi sẽ tập trung vào các chức năng, nhưng các hành

động cũng hoạt động theo cách tương tự.

Đây là một biểu mẫu OData đơn giản lấy ngày làm đầu vào. Nó kích hoạt một quá trình chuyển đổi trạng thái

trong đó máy chủ xem xét tất cả các mục nhập của microblog từ một ngày nhất định, chọn một mục ngẫu nhiên

và đưa ra hình ảnh đại diện cho mục đó.

"#Posts.RandomPostForDate":
{ "title": "Nhận một bài đăng ngẫu nhiên cho ngày nhất
định", "target": "Posts/RandomPostForDate" },

Nếu đây là một truy vấn đơn giản như “tất cả các mục blog từ một ngày nhất định” thì biểu mẫu này sẽ không

cần thiết. Quá trình chuyển đổi trạng thái sẽ được mô tả ngầm bằng giao thức truy vấn của OData. Nhưng giao

thức đó không thể diễn đạt khái niệm “lựa chọn ngẫu nhiên”, vì vậy quá trình chuyển đổi trạng thái này

phải được mô tả rõ ràng bằng cách sử dụng biểu mẫu siêu phương tiện. Bây giờ, đây là câu hỏi: bạn có thể

nhìn vào biểu mẫu này và tìm ra yêu cầu HTTP nào cần thực hiện không?

Đó là một câu hỏi mẹo. Bạn không thể hình dung ra được vì tôi chưa cho bạn xem toàn bộ biểu mẫu.

Một phần của biểu mẫu cung cấp cho bạn URL cơ sở để sử dụng (Bài đăng/RandomPostforDate), nhưng nó không

giải thích cách định dạng phần đóng góp của bạn—ngày mà bạn muốn có một bài đăng ngẫu nhiên. Nó tương đương

với dạng HTML này:

<form action="Posts/RandomPostForDate" Method="GET"> <input


class="RandomPostForDate" type="submit" value="Nhận một
bài đăng ngẫu nhiên cho ngày nhất định."/> </form>

Điều đó rõ ràng là không đầy đủ. Nó thiếu mô tả chính thức cho “ngày nhất định”. "Ngày nhất định" nên dùng

định dạng nào? Mô tả ngữ nghĩa của nó là gì? Bạn có kích hoạt quá trình chuyển đổi trạng thái bằng cách

gửi GET tới Post/RandomPostforDate?Date=9/13/2009 hoặc tới Post/RandomPostForDate?

the_date_to_use=13%20August%202009 hoặc tới Post/ RandomPostForDate?when=yesterday không? Bạn chỉ không có

thông tin đó.

Trong ví dụ HTML, thông tin còn thiếu sẽ nằm trong thẻ <input> thứ hai trong thẻ <form> . Nhưng với OData,

thông tin đó được lưu giữ trong một tài liệu khác — một “tài liệu siêu dữ liệu” được viết không phải bằng

JSON mà bằng XML, sử dụng từ vựng gọi là Ngôn ngữ định nghĩa lược đồ dấu phẩy (CSDL).4

Một biểu diễn OData liên kết đến tài liệu siêu dữ liệu của nó bằng thuộc tính odata.metadata

{
"odata.metadata":

4. Để biết thêm thông tin về cơ sở dữ liệu, hãy truy cập trang web OData.

212 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

"http://api.example.com/YouTypeItWePostIt.svc/$metadata#Posts",
...
}

Đây là một phần của tài liệu siêu dữ liệu hoàn thành định nghĩa về Ngẫu nhiên
Chuyển đổi trạng thái PostForDate :

<FunctionImport Name="RandomPostforDate" EntitySet="Bài viết"


IsBindable="true" m:IsAlwaysBindable="false"
ReturnType="Post" IsSideEffecting="false">
<Parameter Name="date" Type="Edm.DateTime" Mode="In" /> </
FunctionImport>

Bây giờ bạn đã biết toàn bộ câu chuyện. Bạn kích hoạt quá trình chuyển đổi trạng thái RandomForDate bằng

cách định dạng ngày dưới dạng chuỗi, theo định dạng được xác định bởi Mô hình dữ liệu thực thể của

OData.5 Bạn biết rằng quá trình chuyển đổi trạng thái này là an toàn vì mô tả cơ sở dữ liệu của nó có

thuộc tính IsSideEffect ing được đặt thành false. Điều đó có nghĩa là bạn nên kích hoạt quá trình chuyển

đổi trạng thái bằng yêu cầu GET thay vì POST.

Kết hợp tài liệu siêu dữ liệu với bản trình bày OData và bạn có tất cả thông tin cần thiết để kích hoạt

quá trình chuyển đổi trạng thái RandomPostForDate. Bạn gửi một yêu cầu HTTP trông giống như thế này:

NHẬN /YouTypeItWePostIt.svc/Posts/RandomPostForDate?date=datetime'2009-08-13T12: 00' HTTP/


1.1 Máy chủ:
api.example.com

Mặc dù RandomPostForDate là một quá trình chuyển đổi đơn giản nhưng quá trình chuyển đổi trạng thái

OData có thể rất phức tạp. Tài liệu siêu dữ liệu lưu trữ các chi tiết lộn xộn giải thích chính xác cách

kích hoạt bất kỳ chuyển đổi trạng thái nào mà bạn có thể thấy được đề cập trong tài liệu OData. Điều này

giúp máy chủ không phải đưa vào mô tả đầy đủ về quá trình chuyển đổi trạng thái phức tạp trong mọi biểu

diễn hỗ trợ nó. Một khách hàng quan tâm đến một quá trình chuyển đổi trạng thái nhất định có thể tra cứu

mô tả đầy đủ về nó.

Tài liệu siêu dữ liệu dưới dạng tài liệu mô tả dịch vụ Tôi

đã trình bày OData theo cách khiến nó trông giống như Collection+JSON hoặc Siren. Một bài đăng trên blog

nhỏ được thể hiện dưới dạng một đối tượng JSON chứa các trường dữ liệu như DatePublish ed, cùng với các

điều khiển siêu phương tiện và “siêu dữ liệu” khác giải thích các bước tiếp theo có thể thực hiện được.

Đó là phiên bản OData mà tôi khuyên dùng và nó có loại phương tiện application/ json;odata=fullmetadata.

Nhưng có một cách khác để ghi lại tài liệu OData: một cách giữ tất cả các điều khiển siêu phương tiện,

không chỉ những điều khiển phức tạp, trong tài liệu siêu dữ liệu.

5. EDM được định nghĩa trong cùng tài liệu với cơ sở dữ liệu.

Định dạng mẫu bộ sưu tập | 213


Machine Translated by Google

Loại phương tiện của tài liệu như vậy là application/json;odata=minimalmetadata.


Đây là hình thức trình bày của microblog ở định dạng này:

{
"odata.metadata":
"http://api.example.com/YouTypeItWePostIt.svc/$metadata#Posts",
"value":
[ {
"Nội dung": "Đây là bài đăng đầu tiên.",
"Id": 1,
"PostedAt": "2013-04-30T01:42:57.0901805-05:00" }, {

"Nội dung": "Đây là bài đăng thứ hai.",


"Id":
2, "PostedAt": "2013-04-30T01:45:03.0901805-05:00" },

]
}

Nhỏ hơn rất nhiều, nhưng trong thế giới REST, nhỏ hơn không nhất thiết phải tốt hơn.
Siêu dữ liệu đã đi đâu? Điều gì đã xảy ra với PostedBy@odata.navigationLinkUrl và
#Posts.RandomPostForDate? Làm thế nào bạn có thể quyết định yêu cầu HTTP nào sẽ được
thực hiện tiếp theo?

Tất cả thông tin đó được đưa vào tài liệu cơ sở dữ liệu ở đầu kia của oda

liên kết ta.metadata . Tôi đã cho bạn xem một phần tài liệu cơ sở dữ liệu trước đó khi tôi

thảo luận về RandomPostForDate, nhưng đây là một phần chi tiết hơn (đoạn trích này cho thấy

những gì đã xảy ra với PostedBy và RandomPostForDate):

<edmx:Phiên bản Edmx="1.0"


xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
<edmx:DataServices
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0">

<Schema Namespace="YouTypeItWePostIt">
<EntityType Name="Post">
<Key><PropertyRef Name="Id"/></Key>
<Property Name="Id" Type="Edm.Int32" Nullable="false "/>
<Property Name="Content" Type="Edm.String"/>
<Property Name="PostedAt" Type="Edm.DateTimeOffset" Nullable="false"/>
<NavigationProperty Name="PostedBy"
Mối quan hệ="YouTypeItWePostIt.Post_PostedBy"
ToRole="PostedBy" FromRole="Post"/>
</EntityType>

...

<EntityContainer Name="YouTypeItWePostItContext"
m:IsDefaultEntityContainer="true">

214 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

<EntitySet Name="Bài viết" EntityType="YouTypeItWePostIt.Post"/>

<FunctionImport Name="RandomPostforDate" EntitySet="Bài viết"


IsBindable="true" m:IsAlwaysBindable="false"
ReturnType="Post" IsSideEffecting="false">
<Parameter Name="date" Type="Edm.DateTime" Mode="In" /> </
FunctionImport>

<EntitySet Name="Users" EntityType="YouTypeItWePostIt.User"/>

</EntityContainer>

...

</Schema>
</edmx:DataServices>
</edmx:Edmx>

Không có gì sai khi giữ thông tin bổ sung về một tài nguyên bên ngoài phần trình bày của tài

nguyên đó. Suy cho cùng thì đó chính là chức năng của một cấu hình hoặc ngữ cảnh JSON-LD. Vấn đề

ở đây là tài liệu cơ sở dữ liệu có thể được xem như một tài liệu mô tả dịch vụ: tổng quan về API
nói chung khiến nó trông giống như một cơ sở dữ liệu quan hệ.

Như tôi đã đề cập ở Chương 9, người dùng nhìn thấy một tài liệu như thế này có xu hướng tự động

tạo mã máy khách dựa trên nó. Việc thực hiện này sẽ tạo ra sự kết nối chặt chẽ giữa ứng dụng

khách được tạo và phiên bản mô tả dịch vụ cụ thể này. Nếu việc triển khai máy chủ thay đổi, tài

liệu cơ sở dữ liệu sẽ thay đổi theo, nhưng các máy khách sẽ không thay đổi cho phù hợp. Họ sẽ

phá vỡ.

May mắn thay, không ai bắt bạn sử dụng OData theo cách này. Nếu bạn sử dụng ứng dụng loại phương

tiện/json;odata=fullmetadata, các biểu diễn OData của bạn sẽ chứa các điều khiển siêu phương

tiện của riêng chúng. Máy khách sẽ chỉ cần tham khảo tài liệu siêu dữ liệu cơ sở dữ liệu khi nó

cần kích hoạt quá trình chuyển đổi trạng thái phức tạp—một chức năng hoặc hành động—không thể

được mô tả đầy đủ bằng OData.

Định dạng Hypermedia thuần túy

Các loại phương tiện này có ngữ nghĩa ứng dụng rất chung chung, nếu không thì chúng không có ngữ

nghĩa ứng dụng nào cả. Họ tập trung vào việc thể hiện ngữ nghĩa giao thức của HTTP. Bạn cung cấp

ngữ nghĩa ứng dụng của riêng mình bằng cách cắm các mối quan hệ liên kết và bộ mô tả ngữ nghĩa

vào các vị trí được xác định trước.

HTML
• Các loại phương tiện: text/html và application/xhtml+xml •

Được xác định trong: các tiêu chuẩn mở cho HTML 4, cho XHTML, và cho HTML 5

Định dạng Hypermedia thuần túy | 215


Machine Translated by Google

• Phương tiện: giống XML

• Ngữ nghĩa giao thức: điều hướng thông qua các liên kết GET; chuyển đổi trạng thái tùy ý thông qua các biểu

mẫu (GET cho chuyển đổi an toàn, POST cho chuyển đổi không an toàn) • Ngữ nghĩa ứng dụng:

tài liệu mà con người có thể đọc được (“đoạn”, “danh sách”, “bảng”,

“phần,” v.v.) •

Được đề cập trong: Chương 7

Định dạng hypermedia ban đầu và sự lựa chọn được đánh giá thấp cho API. HTML có thể sử dụng trực tiếp các vi định

dạng và dữ liệu vi mô, thay vì sử dụng giá trị gần đúng như cấu hình ALPS. Thẻ <script> của HTML cho phép bạn

nhúng mã thực thi để chạy trên máy khách, một tính năng của kiến trúc RESTful (“mã theo yêu cầu”; xem Phụ lục C)

không được bất kỳ định dạng siêu phương tiện nào khác hỗ trợ. Và các tài liệu HTML có thể được hiển thị bằng đồ

họa cho con người—có giá trị đối với các API được thiết kế để sử dụng bởi ứng dụng khách Ajax hoặc thiết bị di

động và hữu ích khi gỡ lỗi bất kỳ loại API nào.

Đây là sơ đồ trạng thái của HTML:

HTML có ba loại. HTML 4 đã trở thành tiêu chuẩn ổn định kể từ năm 1997. HTML 5, phiên bản thay thế của nó, vẫn

đang được phát triển. Ngoài ra còn có XHTML, một định dạng giống HTML nhưng lại là XML hợp lệ.

Theo quan điểm của cuốn sách này, sự khác biệt quan trọng duy nhất giữa ba tiêu chuẩn này là các quy tắc mới của

HTML 5 về xác thực đầu vào phía máy khách và thực tế là HTML 5 cuối cùng sẽ hỗ trợ dữ liệu vi mô.

HAL
• Các loại phương tiện: application/hal+json và application/hal+xml • Được xác định trong:

phiên bản JSON được xác định trong Internet-Draft “draft-kelly-json-hal”;

phiên bản XML được định nghĩa trong [tiêu chuẩn cá nhân tại đây] • Phương

tiện: XML hoặc JSON • Ngữ nghĩa giao thức:

chuyển đổi trạng thái tùy ý thông qua các liên kết có thể sử dụng bất kỳ

phương thức HTTP; các liên kết không đề cập đến phương thức HTTP sẽ được sử dụng—phương thức đó được lưu giữ
trong tài liệu mà con người có thể đọc được

• Ngữ nghĩa ứng dụng: không có gì đáng nói

216 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

• Bao gồm: Chương 7

HAL là một định dạng tối giản. Sơ đồ trạng thái của nó quá chung chung, trông giống như một điều gì

đó không đúng với đặc tả HTTP:

HAL dựa vào các mối quan hệ liên kết tùy chỉnh (và các giải thích mà con người có thể đọc được trong hồ sơ) để

thực hiện công việc nặng nhọc.

Còi báo động

• Loại phương tiện: application/vnd.siren+json • Được

xác định trong: tiêu chuẩn cá nhân •

Phương tiện: JSON (một phiên bản XML được lên kế hoạch)

• Ngữ nghĩa giao thức: điều hướng thông qua các liên kết GET; chuyển đổi trạng thái tùy ý thông

qua các “hành động” (GET cho các hành động an toàn, POST/PUT/DELETE cho các hành động không an toàn)

• Ngữ nghĩa ứng dụng: rất chung chung

Tài liệu Siren mô tả một “thực thể”, một đối tượng JSON có ngữ nghĩa gần giống như thẻ <div> của

HTML . Một thực thể có thể có một “lớp” và một danh sách “thuộc tính”.

Nó có thể chứa danh sách các “liên kết”, hoạt động giống như thẻ HTML <a> (có rel và href). Nó cũng

có thể chứa một danh sách các hành động, hoạt động giống như các thẻ HTML <form> (có tên, href , một

phương thức và một số trường).

Một thực thể cũng có thể có một số thực thể phụ, tương tự như cách một thẻ <div> có thể chứa một thẻ

khác. Bạn có thể triển khai mẫu bộ sưu tập theo cách này.

Sơ đồ trạng thái của Siren trông giống như sự kết hợp giữa HAL và HTML:

Định dạng Hypermedia thuần túy | 217


Machine Translated by Google

Tiêu đề liên kết

• Loại phương tiện: không

áp dụng • Được mô tả trong: RFC 5988

• Trung bình: Tiêu đề HTTP

• Ngữ nghĩa giao thức: điều hướng thông qua các liên kết GET •

Ngữ nghĩa ứng dụng: không có • Được

đề cập trong: Chương 4

Tiêu đề Liên kết không phải là một định dạng tài liệu, nhưng tôi sẽ đưa nó vào danh sách thú vị vì nó

cho phép bạn thêm các liên kết GET đơn giản vào các biểu diễn thiếu các điều khiển siêu phương tiện,

như hình ảnh nhị phân hoặc tài liệu JSON. Tham số rel của tiêu đề là một vị trí cho mối quan hệ liên kết:

Liên kết: <http://www.example.com/story/part2>;rel="next"

RFC 5988 xác định một số tham số hữu ích khác cho tiêu đề Liên kết , bao gồm loại (cung cấp gợi ý về

loại phương tiện ở đầu bên kia của liên kết) và tiêu đề (chứa tiêu đề mà con người có thể đọc được cho

liên kết).

Theo như tôi được biết, công dụng quan trọng nhất của tiêu đề Liên kết là kết nối tài liệu JSON với

một hồ sơ. JSON cực kỳ phổ biến mặc dù không có điều khiển siêu phương tiện và loại phương tiện ứng

dụng/json không hỗ trợ tham số hồ sơ , vì vậy Liên kết là cách đáng tin cậy duy nhất để trỏ đến hồ sơ

giải thích tài liệu JSON là gì.


tâm có nghĩa là.

Loại nội dung: application/json Liên


kết: <http://www.example.com/profiles/hydraulics>;rel="profile"

Tiêu đề vị trí và nội dung-vị trí

• Loại phương tiện: không

áp dụng • Được mô tả trong: RFC 2616

• Trung bình: Tiêu đề HTTP

• Ngữ nghĩa giao thức: phụ thuộc vào mã phản hồi HTTP • Ngữ nghĩa ứng

dụng: không có • Được đề cập trong:

Chương 1, Chương 2, Chương 3, Phụ lục B

Đây là hai điều khiển hypermedia đơn giản được xác định trong chính tiêu chuẩn HTTP. Tôi đã đề cập sơ

qua đến Vị trí , nhưng tôi sẽ cung cấp cả hai thông tin chi tiết trong Phụ lục B.

Tiêu đề Vị trí nội dung trỏ đến vị trí chuẩn của tài nguyên hiện tại.

Nó tương đương với một liên kết sử dụng chuẩn quan hệ liên kết đã đăng ký IANA.

218 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

Tiêu đề Vị trí được sử dụng làm liên kết đa năng bất cứ khi nào ngữ nghĩa giao thức của phản hồi HTTP yêu

cầu liên kết. Hành vi chính xác phụ thuộc vào mã trạng thái HTTP. Khi mã phản hồi là 201 (Đã tạo), tiêu đề

Vị trí sẽ trỏ đến tài nguyên mới được tạo. Nhưng khi mã phản hồi là 301 (Đã di chuyển vĩnh viễn), tiêu đề

Vị trí sẽ trỏ đến URL mới của tài nguyên đã được di chuyển. Một lần nữa, chi tiết có trong Phụ lục B.

Danh sách URL

• Loại phương tiện: văn bản/uri-list •

Phương tiện: không có

• Được mô tả trong: RFC 2483

• Ngữ nghĩa giao thức: không có

• Ngữ nghĩa ứng dụng: không có

Tài liệu văn bản/danh sách uri chỉ là một danh sách các URL:

http://example.org/
https://www.example.com/
...

Đây có lẽ là loại hypermedia cơ bản nhất từng được nghĩ ra. Nó không hỗ trợ các mối quan hệ liên kết, vì

vậy không có cách nào để thể hiện mối quan hệ giữa các URL này và tài nguyên phục vụ danh sách. Không có

biện pháp kiểm soát siêu phương tiện rõ ràng nên máy khách không có cách nào biết được loại yêu cầu nào

được phép gửi tới các URL này. Điều tốt nhất bạn có thể làm là gửi yêu cầu GET tới từng yêu cầu và xem bạn

nhận được loại đại diện nào.

Tài liệu trang chủ JSON

• Loại phương tiện: application/json-home • Được

mô tả trong: Internet-Draft “draft-nottingham-json-home” • Phương tiện: JSON

• Ngữ nghĩa giao thức: hoàn toàn chung chung • Ngữ

nghĩa ứng dụng: không có

Tài liệu Trang chủ JSON là phiên bản phức tạp hơn của danh sách URL. Định dạng này được thiết kế để sử dụng

làm “trang chủ” của API, liệt kê tất cả các tài nguyên được cung cấp và hành vi của chúng theo giao thức

HTTP.

Tài liệu gia đình JSON là một đối tượng JSON. Các khóa là các mối quan hệ liên kết và các giá trị là các

đối tượng JSON được gọi là “Đối tượng tài nguyên”. Đây là một ví dụ từ thế giới trò chơi mê cung:

Định dạng Hypermedia thuần túy | 219


Machine Translated by Google

{ "phía đông": { "href": "/cells/


N" }, "tây": { "href": "/cells/
L" } }

Đối tượng tài nguyên là một điều khiển siêu phương tiện mô tả ngữ nghĩa giao thức của một tài
nguyên hoặc một nhóm tài nguyên liên quan. Đây là biểu mẫu tìm kiếm, được mô tả bởi Mẫu URI:

{ "tìm kiếm": {"href-template": "/search{?query}", "href-


vars":
{ "query" : "http://alps.io/opensearch#searchTerms" }

Đối tượng tài nguyên có thể bao gồm “gợi ý tài nguyên” mô tả ngữ nghĩa giao thức của nó chi

tiết hơn. Gợi ý phổ biến nhất là cho phép, giải thích phương thức HTTP nào mà tài nguyên sẽ

phản hồi. Đây là Tài liệu trang chủ JSON sử dụng mối quan hệ liên kết lật mà tôi đã xác định

cho phần mở rộng của trò chơi mê cung:

{ "flip": { "href": "/switches/4",


"hints": { "allow": ["POST"] }
}
}

Tài liệu gia đình JSON không nói gì về ngữ nghĩa ứng dụng của các tài nguyên mà nó liên kết
tới. Thông tin đó được lưu giữ trong phần trình bày ở phía bên kia của các liên kết.

Bằng cách kết hợp Tài liệu gốc JSON (mô tả ngữ nghĩa giao thức của API) với tài liệu ALPS (mô
tả ngữ nghĩa ứng dụng của nó), bạn có thể sử dụng API hiện có—ngay cả API không sử dụng
hypermedia—và di chuyển hầu hết các phần mà con người có thể đọc được. tài liệu sang định
dạng có cấu trúc, máy có thể đọc được.

Tiêu đề mẫu liên kết


• Loại phương tiện:

không áp dụng • Được mô tả trong: Internet-Draft “dự thảo-nottingham-link-mẫu” (xem thêm RFC
6570)

• Trung bình: Tiêu đề HTTP

• Ngữ nghĩa giao thức: điều hướng thông qua GET •

Ngữ nghĩa ứng dụng: không có

Tiêu đề Mẫu liên kết hoạt động chính xác theo cách tương tự như tiêu đề Liên kết , ngoại trừ
giá trị của nó được hiểu là Mẫu URI (RFC 6570) thay vì dưới dạng URL. Đây là biểu mẫu tìm kiếm
trong tiêu đề HTTP:

220 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

Mẫu liên kết: </search{?family-name}>; rel="tìm kiếm"

Tiêu đề Mẫu liên kết có một biến đặc biệt gọi là var-base, cho phép bạn chỉ định cấu hình cho

các biến trong Mẫu URI. Trong ví dụ, tên biến family-name gợi ý loại giá trị nào bạn nên đưa vào

biến, nhưng về mặt kỹ thuật nó không có ý nghĩa gì cả. Nó cũng có thể được gọi là đặt-thứ gì đó

ở đây.

Thêm một cơ sở var và đột nhiên có một liên kết đến định nghĩa chính thức về họ.

Mẫu liên kết: </search{?family-name}>; rel="search"; var-


base="http://alps.io/microformats/hCard#"

Bây giờ, biến family-name sẽ mở rộng tới URL http://alps.io/microformats/ hCard#family-name. Tài

liệu ALPS ở đầu kia của URL đó giải thích ngữ nghĩa ứng dụng của biến họ .

Đây là một ví dụ khác sử dụng ngữ nghĩa ứng dụng của Schema.org thay vì ALPS:

Mẫu liên kết: </search{?familyName}>; rel="tìm kiếm"; var-base="http://schema.org/"

Ở đây, biến familyName mở rộng tới URL http://schema.org/familyName, về cơ bản có nghĩa tương tự

như http://alps.io/microformats/hCard#family-
tên.

Vào thời điểm viết bài này, Bản nháp Internet xác định tiêu đề Mẫu liên kết đã hết hạn.

Tác giả của bản thảo, Mark Nottingham, đã bảo tôi cứ tiếp tục và viết nó vào cuốn sách. Anh ấy

cho biết anh ấy sẽ khôi phục Internet-Draft nếu có nhiều người quan tâm đến Link-Template hơn.

WADL
• Loại phương tiện: application/vnd.sun.wadl+xml •

Được định nghĩa trong: tiêu chuẩn mở

• Phương tiện: XML

• Ngữ nghĩa giao thức: hoàn toàn chung chung •

Ngữ nghĩa ứng dụng: không có, hỗ trợ tối thiểu cho các tiện ích mở rộng

WADL là định dạng hypermedia đầu tiên hỗ trợ một bộ ngữ nghĩa giao thức hoàn chỉnh.

Thẻ WADL <request> (tương tự như biểu mẫu HTML) có thể mô tả một yêu cầu HTTP sử dụng bất kỳ

phương thức nào, cung cấp các giá trị cho mọi tiêu đề yêu cầu HTTP được chỉ định và bao gồm nội

dung thực thể của bất kỳ loại phương tiện nào. Giống như AtomPub, điều này bây giờ nghe có vẻ

không đặc biệt lắm nhưng nó đã mang tính đột phá vào thời điểm đó. WADL có thể mô tả ngữ nghĩa

giao thức của bất kỳ API web nào, ngay cả khi API được thiết kế kém và vi phạm tiêu chuẩn HTTP.

Đây là một đoạn WADL giải thích cách lật một công tắc trong phiên bản trò chơi mê cung ở Chương

7:

Định dạng Hypermedia thuần túy | 221


Machine Translated by Google

<method id="flip" name="POST" href="/switches/4"> <doc>Lật


công tắc</doc> </method>

WADL cũng có thể mô tả nội dung của các biểu diễn XML. Tài liệu WADL có thể chỉ ra phần nào của cách

trình bày thú vị—đáng chú ý là phần nào liên kết đến các tài nguyên khác. Tài liệu WADL có thể đưa

vào tài liệu Lược đồ XML để giải thích các kiểu dữ liệu của dữ liệu XML mà nó mô tả. Điều này hữu ích

khi một biểu diễn XML không có lược đồ liên quan của riêng nó.

Thẻ <doc> của WADL làm cho nó trở thành định dạng hồ sơ cơ bản, có khả năng mô tả ngữ nghĩa ứng dụng

của một yêu cầu HTTP hoặc bên trong biểu diễn XML. Nhưng WADL hoàn toàn không thể mô tả bên trong

biểu diễn JSON.6 WADL không được sử dụng rộng rãi, nhưng có

một số triển khai Java JAX-RS tạo ra các mô tả API WADL. Vấn đề nằm ở đó. Mô tả API được tạo tự động

có thể được kết hợp chặt chẽ với việc triển khai phía máy chủ. Hơn nữa, một API sử dụng WADL thường

phục vụ một tài liệu WADL khổng lồ mô tả ngữ nghĩa giao thức của toàn bộ API.

Đây là tài liệu mô tả dịch vụ và như tôi đã đề cập trong Chương 9 , người dùng tạo , nó khuyến khích

các ứng dụng khách được tạo tự động, dựa trên giả định rằng họ đã có được cái nhìn tổng quan đầy đủ

và không thay đổi về ngữ nghĩa của API.

Nhưng API thay đổi. Khi điều đó xảy ra, mô tả WADL của API cũng sẽ thay đổi, nhưng các ứng dụng khách

được tạo tự động thì không. Các khách hàng sẽ phá vỡ.

XLink

• Loại phương tiện: không

áp dụng • Được xác định trong: Tiêu chuẩn W3C

• Phương tiện: Tài liệu XML

• Ngữ nghĩa giao thức: điều hướng và nhúng với GET • Ngữ nghĩa ứng dụng:

không có

XLink là một tiêu chuẩn plug-in cho phép bạn thêm các liên kết hypermedia vào bất kỳ tài liệu XML nào.

Không giống như HTML và Maze+XML, XLink không xác định các thẻ XML đặc biệt đại diện cho các liên kết

siêu phương tiện. XLink xác định một nhóm thuộc tính có thể được áp dụng cho bất kỳ thẻ XML nào để

biến thẻ đó thành một liên kết.

Đây là bản trình bày XML đặc biệt của một ô trong trò chơi mê cung. Thẻ <root> và <direction> là tên

thẻ tôi tạo ra nhằm mục đích trình diễn—chúng không có

6. Tiêu chuẩn Con trỏ JSON, được xác định trong con trỏ ứng dụng Internet-Draft, có thể khắc phục điều này.

222 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

khả năng hypermedia của riêng mình, nhưng tôi có thể biến chúng thành liên kết bằng cách thêm thuộc tính XLink.

<?xml version="1.0"?>
<root xmlns:xlink="http://www.w3.org/1999/xlink"> <direction

xlink:href="http://maze-server.com/maze /cell/N"
xlink:title="Đi về phía
đông!" xlink:arcrole="http://alps.io/example/maze/#east"
xlink:show="replace" />

<link
xlink:href="http://maze-server.com/maze/cell/L"
xlink:title="Đi về phía tây!"
xlink:arcrole="http://alps.io/example/maze/#west"
xlink:show="replace" />
</
root>

Các thuộc tính href và title trông quen thuộc. Mối quan hệ liên kết đi vào thuộc tính arcrole tùy chọn . Có một sự

thay đổi nhỏ ở đây: thuộc tính arcrole chỉ hỗ trợ các mối quan hệ liên kết mở rộng—những mối quan hệ trông giống như

các URL. Mối quan hệ liên kết của bạn không được giống tác giả hoặc đông; nó phải trông giống như http://alps.io/maze/

#west.

Thuộc tính show cho phép bạn chuyển đổi giữa liên kết điều hướng hoạt động giống như thẻ <a> của HTML (show="replace",

mặc định) và liên kết nhúng hoạt động giống như thẻ <img> của HTML (show="embed"). Phương thức HTTP được sử dụng

luôn là GET.

Với XLink, tôi có thể cung cấp vốn từ vựng XML đặc biệt gần giống với các khả năng siêu phương tiện đã được thiết kế

thành Mê cung+XML. Có một vài tính năng nâng cao của XLink mà tôi chưa đề cập đến: đáng chú ý là loại liên kết mở

rộng, cho phép bạn kết nối nhiều hơn hai tài nguyên bằng một liên kết duy nhất và thuộc tính vai trò mà tôi sẽ trình

bày trong Chương 12 .

XForms

• Loại phương tiện: không

áp dụng • Phương tiện: Tài liệu XML.

• Ngữ nghĩa giao thức: chuyển đổi trạng thái tùy ý thông qua các biểu mẫu (GET cho chuyển đổi an toàn, POST/PUT/

DELETE cho chuyển đổi không an toàn)

• Ngữ nghĩa ứng dụng: không có

XForms thực hiện đối với các biểu mẫu siêu phương tiện giống như XLink thực hiện đối với các liên kết. Đó là một

tiêu chuẩn plug-in bổ sung các biểu mẫu giống HTML vào bất kỳ tài liệu XML nào. Tuy nhiên, không giống như XLink, nó

xác định các thẻ riêng của mình. Đây là cách XForms có thể biểu diễn một biểu mẫu tìm kiếm đơn giản:

Định dạng Hypermedia thuần túy | 223


Machine Translated by Google

<xforms:mô hình>
<xforms:submission action="http://example.com/search" Method="get" id="submit-
button"/>
<xforms:instance>
<query/>
</xforms:instance>
<xforms:model>

Thẻ <model> là một vùng chứa, giống như thẻ <form> của HTML . Thẻ <submission> giải thích yêu
cầu HTTP cần thực hiện: trong trường hợp này là yêu cầu GET tới http://example.com/search.

Phần con của thẻ <instance> giải thích cách xây dựng chuỗi truy vấn (đối với yêu cầu GET) hoặc
phần nội dung thực thể (đối với yêu cầu POST hoặc PUT).

Thẻ <query> là thẻ tôi tạo ra cho ví dụ này; nó đại diện cho một trường biểu mẫu được gọi là

truy vấn. Ý nghĩa của thẻ này—ví dụ: cho dù đó là trường văn bản hay hộp kiểm—được xác định

riêng biệt, trong thẻ <input> của XForms :

<xforms:input ref="query">
<xforms:label>Cụm từ tìm kiếm</xforms> </
xforms:input>

<xforms:submit submit="submit-button">
<label>Tìm kiếm!</label> </
xforms:submit>

Thẻ <input> có ref="query" cho biết trường truy vấn là một kiểu nhập văn bản có <nhãn> mà con

người có thể đọc được . Thẻ <submit> cung cấp <label> cho nút gửi. Cùng với nhau, thẻ <model>

và hai thẻ <input> gần đúng chức năng của biểu mẫu HTML này:

<form action="http://example.com/search" Method="GET"> <input


type="text" name="query"/> <label
for="query">Cụm từ tìm kiếm</label> < gửi giá
trị="Tìm kiếm!"">
</form>

Đây là một ví dụ rất cơ bản; có nhiều tính năng nâng cao của XForms mà tôi sẽ không đề cập
đến. Hướng dẫn của W3C “XForms dành cho tác giả XHTML”7 sử dụng các biểu mẫu HTML để giải thích
XForms một cách chi tiết, vượt xa khả năng của HTML thuần túy thành một số tính năng nâng cao
của XForms.

GeoJSON: Một loại rắc rối


Chúng tôi đã thấy những mẫu vật khỏe mạnh trong vườn thú hypermedia. Bây giờ tôi muốn xem xét
GeoJSON, một định dạng tài liệu dành riêng cho miền có một số lỗi thiết kế gây ảnh hưởng đến nó.

7. Hướng dẫn có sẵn tại trang w3.org này.

224 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

khả năng sử dụng trong APIs.8 Tôi không làm điều này để chọn GeoJSON; Bản thân tôi cũng đã mắc phải

những sai lầm tương tự. Đó là những lỗi phổ biến, vì vậy ngay cả khi GeoJSON không phải là thứ bạn cần

tìm hiểu ngay bây giờ, hãy tiếp tục.

GeoJSON là một tiêu chuẩn dựa trên JSON, được thiết kế để thể hiện các đặc điểm địa lý như các điểm trên

bản đồ. Đây là số liệu thống kê của nó:

• Loại phương tiện: application/json •

Được xác định trong: tiêu chuẩn công ty được xác định

tại đây • Phương tiện: JSON

• Ngữ nghĩa giao thức: GET để loại trừ các hệ tọa độ • Ngữ nghĩa ứng dụng: các

đặc điểm địa lý và tập hợp các đặc điểm

Giống như hầu hết tất cả các tài liệu dựa trên JSON được sử dụng trong API, tài liệu GeoJSON là một đối

tượng JSON phải chứa một số thuộc tính nhất định. Đây là tài liệu GeoJSON xác định chính xác vị trí của
một di tích cổ trên Trái đất:

{ "loại": "FeatureCollection",
"features":

[ { "type": "Tính năng",

"hình học":

{ "loại": "Điểm",
"tọa độ": [12.484281,41.895797] },

"properties":

{ "type": null,
"title": "Cột Trajan", "awmc_id":
"91644", "awmc_link":
"http://awmc.unc.edu/api/omnia/91644" , "pid": "423025",
"pleiades_link":
"http://pleiades.stoa.org/places/423025", "description": "Đài tưởng
niệm hoàng đế Marcus Ulpius Traianus"}

} ] }

8. Những sai sót này không gây tổn hại nhiều đến GeoJSON đến mức không ai sử dụng nó. Nó khá phổ biến—chỉ là không tốt như nó có thể
là.

GeoJSON: Loại rắc rối | 225


Machine Translated by Google

Tôi đã điều chỉnh cách trình bày này một chút từ API trong thế giới thực do Trung tâm Bản đồ
Thế giới Cổ đại của UNC cung cấp . Ngữ nghĩa ứng dụng của GeoJSON rất đơn giản và con người
có thể hiểu tài liệu khá dễ dàng. Nó đại diện cho một bộ sưu tập được gọi là FeatureCollection.

Bộ sưu tập chỉ chứa một mục: Đối tượng, có hình học (một Điểm duy nhất trên bản đồ) và một

loạt các thuộc tính linh tinh như mô tả mà con người có thể đọc được .

Nhìn nhanh vào tiêu chuẩn GeoJSON sẽ thấy rằng thay vì Điểm , hình học có thể là LineString

(đại diện cho đường biên giới hoặc đường) hoặc Đa giác (đại diện cho khu vực của một thành
phố hoặc quốc gia).

GeoJSON không có các biện pháp kiểm soát siêu phương tiện

chung Thật không may, ngữ nghĩa giao thức của GeoJSON không hề đơn giản. Bạn có thấy

awmc_link và pleiades_link trong phần trình bày đó không? Chúng trông giống như các liên kết
hypermedia, nhưng thực tế không phải vậy. Theo tiêu chuẩn GeoJSON, đó chỉ là những chuỗi
trông giống như URL. Khi Trung tâm lập bản đồ thế giới cổ đại thiết kế API GeoJSON của họ,

họ phải nhét tất cả các liên kết của mình vào danh sách thuộc tính vì GeoJSON không xác định
các điều khiển hypermedia cho chúng. Điều này có nghĩa là máy khách GeoJSON chung không thể

theo dõi pleiades_link hoặc thậm chí nhận ra nó là một liên kết. Để theo liên kết đó, bạn
cần phải viết một ứng dụng khách cụ thể cho API của Trung tâm Bản đồ Thế giới Cổ đại.

Nếu GeoJSON không xác định bất kỳ điều khiển hypermedia nào thì điều này có thể hiểu được.
Không phải mọi định dạng dữ liệu đều phải là định dạng hypermedia. Đơn giản là tôi sẽ không
đề cập đến GeoJSON trong cuốn sách này. Điều kỳ lạ là GeoJSON xác định điều khiển hypermedia,
nhưng nó chỉ có thể được sử dụng cho một việc cụ thể: thay đổi hệ tọa độ đang sử dụng.

Theo mặc định, tọa độ trong biểu diễn GeoJSON ([12.484281,41.895797]) được đo bằng độ kinh
độ và vĩ độ—một hệ thống mà tất cả chúng ta đều quen thuộc. Vì hành tinh Trái đất không phải
là một hình cầu hoàn hảo nên các phép đo này được diễn giải theo một tiêu chuẩn gọi là
WGS84,9, tiêu chuẩn này đưa ra những thứ như hình dạng gần đúng của Trái đất, vị trí của kinh
tuyến gốc và “mực nước biển” nghĩa là gì.

Nếu bạn không phải là người đam mê bản đồ, bạn có thể cho rằng Trái đất là một hình cầu và
xong việc với nó. Nhưng đối với những người đam mê bản đồ, WGS84 chỉ là mặc định. Có nhiều
hệ tọa độ khác mà bạn có thể sử dụng. Độc giả người Anh có thể quen thuộc với Lưới điện Quốc
gia Khảo sát Quân sự, một hệ thống tọa độ sử dụng “hướng đông” và “hướng bắc” thay vì vĩ độ
và kinh độ, và hệ thống này chỉ có thể biểu thị các điểm trong một khu vực cụ thể có kích
thước 700 x 1300 km mà bao trùm quần đảo Anh. Có vô số hệ tọa độ, vì bạn có thể xác định một
hệ tọa độ đặt kinh tuyến gốc của Trái đất ở bất cứ đâu bạn muốn.

9. Một tiêu chuẩn ngành, nhưng từ một ngành khác với các tiêu chuẩn còn lại được đề cập trong cuốn sách này.
Bạn có thể lấy phiên bản PDF của tiêu chuẩn tại trang này.

226 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

Và bây giờ câu chuyện của chúng ta quay trở lại với hypermedia, bởi vì đây chính là mục đích
kiểm soát hypermedia duy nhất của GeoJSON. GeoJSON cho phép bạn liên kết đến mô tả về hệ tọa
độ bạn đang sử dụng.

Đây là tài liệu GeoJSON chứa liên kết hypermedia chính hãng mà bất kỳ ứng dụng khách GeoJSON
nào cũng sẽ nhận ra như vậy:

{ "type:"Tính năng",
"hình học":

{ "type": Điểm",
"tọa độ":[60000,70000] },

"crs":
{ "type":
"link",
"properties": { "href": "http://example.org/
mygrid.wkt",
"type": "esriwkt" }
}
}

Tọa độ [60000,70000] không phải là số đo kinh độ và vĩ độ hợp lệ, nhưng điều đó không sao vì
chúng tôi không sử dụng kinh độ và vĩ độ. Chúng tôi đang sử dụng hệ quy chiếu tọa độ tùy

chỉnh (crs) được mô tả bởi tài nguyên tại http://example.org/ mygrid.wkt. Đây chính xác là
thứ mà hypermedia phù hợp. Vấn đề với GeoJSON là nơi duy nhất nó cho phép liên kết nằm trong
định nghĩa của hệ quy chiếu tọa độ.

Sơ đồ trạng thái này mô tả ngữ nghĩa giao thức của GeoJSON:

Điều đó không hữu ích lắm! Hầu hết các API GeoJSON không sử dụng hệ tọa độ tùy chỉnh—tất cả
chúng ta đều quen với kinh độ và vĩ độ thông thường. Nhưng tiêu chuẩn GeoJSON cho phép chúng,
vì chúng là một khía cạnh thiết yếu của miền có vấn đề. Mặt khác, hầu như bất kỳ API nào cũng
cần cung cấp các liên kết linh tinh giữa các tài nguyên của nó, nhưng tiêu chuẩn Geo- JSON
thiếu khả năng đó, có lẽ vì nó không liên quan trực tiếp đến miền vấn đề. Định dạng dữ liệu
cơ bản không giúp ích được gì vì JSON không xác định điều khiển siêu phương tiện nào cả. Đó

là lý do tại sao những người triển khai API phải dùng đến các thủ thuật hack như awmc_link.

Phàn nàn đủ rồi; tôi sẽ làm gì khác đi? Một thiết kế tập trung hơn vào siêu phương tiện sẽ

cho phép một danh sách các liên kết, mỗi liên kết có thể chỉ định một mối quan hệ liên kết.
GeoJSON sẽ trông giống Collection+JSON hoặc Siren hơn rất nhiều. Sau đó là bản đồ thế giới cổ đại

GeoJSON: Loại rắc rối | 227


Machine Translated by Google

Center sẽ không cần phải đưa awmc_link và pleiades_link vào đối tượng thuộc tính .

Để liên kết đến một hệ tọa độ, bạn sẽ sử dụng cùng loại liên kết mà bạn sử dụng cho bất kỳ mục đích nào

khác. Các crs của GeoJSON sẽ trở thành một mối quan hệ liên kết, hữu ích trong bất kỳ ứng dụng bản đồ

nào, ngay cả những ứng dụng không sử dụng GeoJSON.

Bạn có thể có các điều khiển hypermedia dành riêng cho ứng dụng. Thẻ <img> của HTML là một điều khiển

siêu phương tiện dành riêng cho ứng dụng. Nhưng bạn cũng cần cung cấp một điều khiển liên kết chung, đơn

giản.

GeoJSON không có loại phương tiện Có một

vấn đề khác với GeoJSON: nó không có loại phương tiện đã đăng ký. Tài liệu GeoJSON được phục vụ dưới dạng

ứng dụng/json, giống như bất kỳ tài liệu JSON nào khác. Làm cách nào khách hàng có thể phân biệt giữa

GeoJSON và JSON cũ đơn giản?

Giải pháp tốt nhất là máy chủ coi GeoJSON như một cấu hình của JSON. Điều này có nghĩa là cung cấp một

liên kết tới tiêu chuẩn GeoJSON với rel="profile". Vì bản thân JSON không có điều khiển siêu phương tiện

nên bạn sẽ cần sử dụng tiêu đề Liên kết :

Liên kết: <http://www.geojson.org/geojson-spec.html>;rel="profile"

Bạn cũng có thể viết cấu hình ALPS hoặc ngữ cảnh JSON-LD cho GeoJSON và cung cấp liên kết đến đó bằng tiêu

đề Liên kết :

Liên kết: <http://example.com/geojson.jsonld>;


rel="http://www.w3.org/ns/json-ld#context"

Theo như tôi biết, không có triển khai GeoJSON nào thực hiện được một trong những điều này. GeoJSON được

phục vụ dưới dạng ứng dụng/json và khách hàng chỉ cần biết trước tài nguyên nào phục vụ các biểu diễn

GeoJSON và tài nguyên nào phục vụ JSON thông thường. Máy khách muốn hiểu các cấu hình khác nhau của JSON

phải chạy phương pháp phỏng đoán đối với mọi biểu diễn JSON đến, cố gắng tìm ra cấu hình nào mà máy chủ

đang cung cấp cho nó.

Nghe có vẻ phi thực tế khi một khách hàng sẽ cần xử lý các cấu hình JSON khác nhau?

Vâng, hãy xem xét điều này. Nền tảng ArcGIS bao gồm một API trình bày cùng loại thông tin như GeoJSON. Nó

phục vụ các biểu diễn JSON bề ngoài giống với các biểu diễn của GeoJSON và nó phục vụ chúng dưới dạng ứng

dụng/json, không có thông tin hồ sơ.

Tôi không nghĩ việc tưởng tượng một khách hàng có thể xử lý cả GeoJSON và ArcGIS JSON là một điều viển

vông. Nếu GeoJSON được phân phối dưới dạng ứng dụng/geo+json và ArcGIS JSON được phân phối dưới dạng ứng

dụng/vnd.arcgis.api+json, thì nhà phát triển ứng dụng khách có thể tách mã ứng dụng khách dựa trên giá

trị của tiêu đề Kiểu nội dung và hợp nhất mã đường dẫn sau khi dữ liệu đến được phân tích cú pháp. Nếu

GeoJSON và ArcGIS JSON nhất quán

228 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

được dùng dưới dạng các cấu hình khác nhau, nhà phát triển có thể chia mã dựa trên giá trị của tiêu đề Liên

kết . Nếu chúng được phân phối với các ngữ cảnh JSON-LD khác nhau, nhà phát triển có thể chia mã dựa trên đó.

Nhưng cả hai định dạng đều được phục vụ như thể chúng có cùng ý nghĩa. Một máy khách hợp nhất phải cố gắng

phân biệt giữa hai định dạng bằng cách sử dụng phương pháp chẩn đoán được xác định kém. Hoặc, nhiều khả năng

hơn, ý tưởng về một khách hàng thống nhất chưa bao giờ xuất hiện với bất kỳ ai. Giống như hai con tàu đi qua

trong đêm, một nhà phát triển viết ứng dụng khách GeoJSON cho API GeoJSON, trong khi một nhà phát triển khác

sao chép phần lớn công việc của nhà phát triển đầu tiên, viết ứng dụng khách ArcGIS để chạy trên các bản cài
đặt ArcGIS.

Không ai có thể đổ lỗi cho việc này. Tiêu chuẩn GeoJSON đã được hoàn thiện vào năm 2008. Vào thời điểm đó,

hiểu biết của chúng tôi về API hypermedia khá kém. Các nhà thiết kế GeoJSON không quên đăng ký loại phương

tiện; họ đã xem xét nó và sau đó đưa ra vấn đề.

Nhưng bây giờ không còn là năm 2008 nữa. Hiện tại chúng tôi có các tiêu chuẩn bổ sung các điều khiển siêu

phương tiện thực sự vào JSON. Chúng ta có thể sử dụng cấu hình để thêm ngữ nghĩa cấp ứng dụng vào các loại

siêu phương tiện chung. Chúng tôi đã thấy hàng trăm định dạng dữ liệu không tương thích lẫn nhau được phân

phát dưới dạng ứng dụng/json và chúng tôi biết mình có thể làm tốt hơn.

Học từ GeoJSON Khi một đối tượng

GeoJSON được đưa vào tài liệu JSON có khả năng siêu phương tiện (chẳng hạn như tài liệu OData, có hỗ trợ rõ

ràng cho GeoJSON được nhúng), cả hai vấn đề này đều biến mất. Việc GeoJSON không có các biện pháp kiểm soát

siêu phương tiện chung không thành vấn đề vì nó được nhúng trong một tài liệu có thể xử lý những nội dung

đó. Việc GeoJSON không có loại phương tiện đặc biệt không thành vấn đề vì nó kế thừa loại phương tiện của

tài liệu gốc. Tại thời điểm này, GeoJSON trở thành một tiêu chuẩn plug-in, tương tự như OpenSearch.

Nếu bạn thiết kế một định dạng dành riêng cho miền mà rõ ràng không phải là một phần bổ trợ cho một số định

dạng khác thì bạn nên cung cấp cho nó một loại phương tiện duy nhất. Sẽ hữu ích nếu bạn cũng đăng ký loại

phương tiện với IANA, nhưng nếu bạn sử dụng vnd . tiền tố, bạn không phải đăng ký bất cứ điều gì.

Ngoài ra, hãy đảm bảo định dạng của bạn có một số loại điều khiển siêu phương tiện chung, như thẻ <link> của

Mê cung+XML. Bạn có thể nghĩ rằng công việc của bạn không phải là cung cấp một điều khiển siêu phương tiện

chung vì điều đó không liên quan gì đến miền vấn đề của bạn. Nhưng nếu bạn không cung cấp khả năng kiểm soát

siêu phương tiện, mỗi người dùng của bạn sẽ nghĩ ra thiết kế chỉ dùng một lần của riêng họ, gọi là

awmc_link. Bạn có thể mượn điều khiển siêu phương tiện clip-on đơn giản bằng cách sử dụng XLink cho tài liệu

XML hoặc JSON-LD cho tài liệu JSON.

Nói chung, có lẽ tốt hơn là nên quên loại phương tiện dành riêng cho miền và thiết kế một tập hợp ngữ nghĩa

ứng dụng dành riêng cho miền — một hồ sơ. Sau đó, những ngữ nghĩa đó có thể được áp dụng vào loại siêu phương

tiện chung như Siren hoặc loại phương tiện mẫu bộ sưu tập như Bộ sưu tập+JSON.

GeoJSON: Loại rắc rối | 229


Machine Translated by Google

Sở thú ngữ nghĩa


Tôi đã cho bạn thấy những điều kỳ diệu của vườn thú hypermedia để chứng minh tính đa dạng và

linh hoạt của các thiết kế dựa trên hypermedia. Bây giờ tôi sẽ đưa bạn đi tham quan một vườn thú

khác (nhanh hơn nhiều): một loạt vườn bướm chứa đầy ngữ nghĩa ứng dụng cho các lĩnh vực vấn đề

khác nhau. Mục tiêu của tôi ở đây cụ thể hơn: giúp bạn tiết kiệm thời gian bằng cách sử dụng lại

công việc mà người khác đã làm.

Trong Chương 9, tôi đã đề cao lợi ích của việc sử dụng lại ngữ nghĩa ứng dụng hiện có. Các hồ sơ

được liệt kê ở đây là kết quả của những người thông minh xem xét cẩn thận một miền có vấn đề và

điều hướng các vấn đề đặt tên phức tạp. Không có lý do gì bạn phải sao chép tác phẩm đó. Việc sử

dụng lại ngữ nghĩa hiện có bất cứ khi nào có thể cũng loại bỏ cám dỗ tiết lộ chi tiết triển khai

máy chủ của bạn, giúp bạn có thể tự do thay đổi những chi tiết đó mà không làm tổn hại đến khách

hàng của mình.

Điều quan trọng nhất là khi các API khác nhau chia sẻ cùng một ngữ nghĩa ứng dụng, có thể viết

các ứng dụng khách có khả năng tương tác hoặc các thư viện xử lý ngữ nghĩa chung thay vì một ứng
dụng khách tùy chỉnh cho từng API riêng lẻ. Hiện tại điều này mang tính hy vọng hơn là hiện

thực, nhưng ít nhất con đường phía trước trước mắt đã rõ ràng.

Thay vì hiển thị cho bạn nhiều hồ sơ riêng lẻ trong vườn thú ngữ nghĩa, tôi sẽ tập trung chủ yếu

vào các cơ quan đăng ký chứa các hồ sơ đó.

Cơ quan đăng ký quan hệ liên kết IANA

• Loại phương tiện:

bất kỳ • Trang web: trang

IANA này • Ngữ nghĩa: điều hướng chung

Tôi đã nói về cơ quan đăng ký IANA về các mối quan hệ liên kết gần như trong toàn bộ cuốn sách.

Đó là sổ đăng ký toàn cầu chứa khoảng 60 mối quan hệ liên kết. Bạn được phép sử dụng bất kỳ mối

quan hệ nào đã đăng ký IANA trong bất kỳ tuyên bố nào và cho rằng khách hàng của bạn biết bạn

đang nói về điều gì.

Các mối quan hệ liên kết chỉ được đưa vào sổ đăng ký IANA nếu chúng được xác định theo tiêu

chuẩn mở như Khuyến nghị RFC hoặc W3C và đủ chung để hữu ích cho mọi loại phương tiện. Mỗi mối

quan hệ liên kết được cung cấp một mô tả ngắn gọn mà con người có thể đọc được và một liên kết

tới tiêu chuẩn đã xác định nó ban đầu.

Trong bước 3 của quy trình thiết kế của Chương 9, tôi đề cập đến một số mối quan hệ liên kết đã

đăng ký IANA đặc biệt hữu ích cho thiết kế API.

Wiki định dạng vi mô

• Loại phương tiện: HTML (Phiên bản ALPS có sẵn cho một số vi định dạng)

230 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

• Trang web: trang vi định dạng

này • Ngữ nghĩa: loại nội dung mà con người có thể muốn tìm kiếm trực tuyến

Dự án Microformats là nỗ lực thành công đầu tiên trong việc xác định các cấu hình cho ngữ nghĩa

ứng dụng. Các vi định dạng được xác định một cách cộng tác, trên wiki và danh sách gửi thư. Trong

số các vi định dạng ổn định, đây là những vi định dạng mà bạn có thể quan tâm nhất:

hLịch

Diễn tả các sự kiện theo thời gian. Dựa trên định dạng iCalendar văn bản thuần túy được xác định trong
RFC 2445.

hCard

mô tả con người và tổ chức. Dựa trên định dạng vCard văn bản thuần túy (được xác định trong

RFC 2426) và được đề cập trong Chương 7.

XFN

Một tập hợp các mối quan hệ liên kết mô tả mối quan hệ giữa con người với nhau, từ bạn bè ,

đồng nghiệp đến người yêu.

XOXO

Mô tả các đường nét. Vi định dạng này rất thú vị vì nó không thêm bất kỳ thứ gì vào HTML. Nó

chỉ gợi ý những cách thực hành tốt nhất để sử dụng ngữ nghĩa ứng dụng hiện có của HTML.

Các thông số kỹ thuật vi định dạng này là bản nháp về mặt kỹ thuật, nhưng hầu hết chúng không thay

đổi trong vài năm, vì vậy tôi có thể nói rằng chúng khá ổn định:

quảng cáo

Địa chỉ vật lý. Đây là định dạng con của hCard, chỉ bao gồm các phần đại diện cho địa chỉ. Ý

tưởng là nếu bạn không cần tất cả hCard, bạn chỉ cần sử dụng adr.

địa lý

Vĩ độ và kinh độ. (Dĩ nhiên là sử dụng tiêu chuẩn WGS84!) Một định dạng phụ khác của hCard.

hAtom

Bài đăng trên blog. Dựa trên định dạng nguồn cấp dữ liệu Atom (RFC 4287). Đây là một ví dụ

thú vị về một định dạng siêu phương tiện (HTML) áp dụng ngữ nghĩa ứng dụng của một định dạng
khác (Atom).

hDanh

sách Danh sách các dịch vụ cho thuê, quảng cáo cá nhân, v.v. Vi định dạng này chủ yếu sử dụng
lại ngữ nghĩa từ các vi định dạng có liên quan: hReview, hCard và hCalendar.

hMedia

Basic siêu dữ liệu về các tệp hình ảnh, video và âm thanh.

Sở thú ngữ nghĩa | 231


Machine Translated by Google

hNews

Một phần mở rộng của hAtom bổ sung thêm một số mô tả cụ thể cho các bài báo, như dòng ngày.

hSản

phẩmDanh sách sản phẩm.

hCông

thức nấu ăn .

hTiếp tục

Sơ yếu lý lịch/CV.

hĐánh giá

Mô tả một đánh giá (về bất cứ điều gì), với một đánh giá.

Có một số vi định dạng thú vị mà tôi chưa đề cập đến vì chúng đã được HTML 5 áp
dụng một cách hiệu quả và hiện là các mối quan hệ liên kết đã đăng ký IANA: tác
giả, nofollow, thẻ và giấy phép. Vi định dạng thanh toán lại cũng trở thành thanh
toán quan hệ liên kết được đăng ký IANA.

Tôi đã tạo các tài liệu ALPS nắm bắt ngữ nghĩa ứng dụng thiết yếu của hầu hết các vi định dạng được liệt kê

ở đây. Chúng có sẵn từ cơ quan đăng ký ALPS.

Liên kết quan hệ từ Microformats Wiki

• Loại phương tiện: HTML •

Trang web: trang vi định dạng này •

Ngữ nghĩa: rất, rất linh tinh

Wiki Microformats cũng có một danh sách khổng lồ các mối quan hệ liên kết được xác định trong các tiêu chuẩn

hoặc được thấy trong cách sử dụng thực tế nhưng chưa được đăng ký với IANA. Trang wiki này là cơ quan đăng ký

chính thức cho các quan hệ liên kết được sử dụng trong HTML 5, nhưng nó cũng là cơ quan đăng ký không chính

thức của tất cả các quan hệ liên kết mong muốn trở nên hữu ích bên ngoài một ứng dụng. Các mối quan hệ liên

kết của Maze+XML sẽ không bao giờ cắt đứt được với IANA—chúng quá dành riêng cho ứng dụng—nhưng chúng được đề
cập trên wiki Microformats.

Trong Chương 8, tôi đã đề cập đến trang wiki này và đưa ra một số ví dụ về các mối quan hệ được xác định ở

đó. Tôi không khuyên bạn chỉ nên chọn các mối quan hệ liên kết từ trang wiki này và sử dụng chúng. Khách hàng

của bạn sẽ không biết bạn đang nói về điều gì. Ưu điểm thực sự của trang này là cách tìm kiếm các tiêu chuẩn

mà trước đây bạn chưa biết.

Nếu bạn đang dự định tạo API trò chơi mê cung của riêng mình và bạn đã tìm kiếm trang này về mê cung hoặc

phía bắc, bạn sẽ khám phá Maze+XML. Bạn không nhất thiết phải sử dụng

232 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

Mê cung+XML, nhưng bạn sẽ có cái nhìn thoáng qua về cách người khác đã giải quyết vấn đề tương

tự.

lược đồ.org

• Phương tiện: HTML5 và RDFa (có sẵn phiên bản ALPS)

• Site: trang chủ lược đồ •

Ngữ nghĩa: loại nội dung mà con người có thể muốn tìm kiếm trực tuyến

Như tôi đã đề cập ở Chương 8, nguồn chính cho các mục dữ liệu vi mô là một cơ quan thanh toán bù

trừ có tên là lược đồ.org. Trang web này sử dụng ngữ nghĩa ứng dụng của các tiêu chuẩn như rNews

(dành cho tin tức) và GoodRelations (dành cho các cửa hàng trực tuyến) và chuyển chúng sang các

mục dữ liệu vi mô. Đổi lại, tôi đã tự động tạo tài liệu ALPS cho các mục vi dữ liệu của Schema.org

và cung cấp chúng trên Alps.io.

Có hàng trăm mục dữ liệu vi mô được mô tả trên lược đồ.org và nhiều mục khác đang được triển

khai khi những người bảo trì lược đồ.org làm việc với những người tạo ra các tiêu chuẩn khác để
thể hiện các tiêu chuẩn đó trong dữ liệu vi mô. Thay vì nói về tất cả các mục dữ liệu vi mô, tôi

sẽ liệt kê các mục cấp cao nhất hiện tại và đề cập đến một số lớp con đáng chú ý của chúng:

• CreativeWork (bao gồm Bài viết, Blog, Sách, Bình luận, Ghi âm nhạc, Soft‐

wareApplication, TVSeries và WebPage)

• Sự kiện (bao gồm Sự kiện kinh doanh, Lễ hội và Tương tác người dùng) •

Vô hình là một loại danh mục tổng hợp, trong đó đáng chú ý bao gồm Đối tượng, Thương hiệu,

Tọa độ địa lý, Đăng việc làm, Ngôn ngữ, Ưu đãi và Số lượng •

MedicalEntity (bao gồm MedicalCondition, MedicalTest và AnatomicalStruc‐


đúng)

• Tổ chức (bao gồm Công ty, tổ chức phi chính phủ và Đội thể thao)

• Người

• Địa điểm (bao gồm Thành phố, Núi và Điểm thu hút khách du lịch)

• Sản phẩm (bao gồm ProductModel)

Như bạn có thể thấy, có rất nhiều điểm trùng lặp giữa các mục vi dữ liệu của lược đồ.org và vi

định dạng. Mục Person có cùng nền tảng với vi định dạng hCard. Mục Sự kiện tương tự như hEvent,

Article thành hAtom, NewsArticle thành hNews, Recipe to hRecipe, GeoCoordines to geo, v.v.

Xin lưu ý: các mục vi dữ liệu của lược đồ.org rất tập trung vào người tiêu dùng. Sản phẩm là thứ

mà khách hàng có thể mua, không phải là dự án mà khách hàng đang thực hiện. Ngữ nghĩa của mục

Nhà hàng liên quan nhiều đến việc ăn uống tại một nhà hàng và hầu như không liên quan gì đến

việc điều hành hoặc kiểm tra một nhà hàng. Có một mục Ứng dụng phần mềm,

Sở thú ngữ nghĩa | 233


Machine Translated by Google

nhưng không có gì liên quan đến lỗi, bài kiểm tra đơn vị, kho lưu trữ kiểm soát phiên bản, cột

mốc phát hành hoặc bất kỳ vấn đề nào khác mà chúng tôi xử lý khi phát triển phần mềm. Trong mắt

tôi, mục duy nhất được mô tả đủ chi tiết để hữu ích cho bác sĩ là MedicalEntity, và bác sĩ có thể

sẽ không đồng ý với tôi về điều đó.

Nói tóm lại, dự án Schema.org có quan điểm rõ ràng. Nó không phải là bách khoa toàn thư và ngay

cả khi nó xác định một mục trùng với miền API của bạn thì ngữ nghĩa ứng dụng mà nó xác định có

thể không liên quan gì đến cách bạn nhìn nhận mọi thứ.

Cốt lõi Dublin

• Phương tiện: HTML, XML, RDF hoặc văn bản thuần

túy • Trang web: Trang chủ Dublin

Core • Ngữ nghĩa: tác phẩm đã xuất bản

Dublin Core là tiêu chuẩn ban đầu để xác định ngữ nghĩa ứng dụng, có từ năm
1995. Nó xác định 15 bit ngữ nghĩa cho thông tin về các tác phẩm đã xuất bản:
tiêu đề, tác giả, mô tả, v.v. Những bit ngữ nghĩa này có thể được sử dụng làm
bộ mô tả ngữ nghĩa hoặc làm quan hệ liên kết.

Sáng kiến siêu dữ liệu cốt lõi Dublin cũng đã xác định một hồ sơ hoàn chỉnh hơn, các Điều khoản

siêu dữ liệu DCMI. Cấu hình này bao gồm các bộ mô tả ngữ nghĩa như dateCopyrighed, cũng như các

quan hệ liên kết như isPartOf và các phần thay thế.

Luồng hoạt động

• Phương tiện: Atom, JSON •

Trang web: Trang chủ Luồng hoạt động •

Gia đình: những việc con người làm trên mạng

Luồng hoạt động là một tiêu chuẩn của công ty để thể hiện cuộc sống trực tuyến của chúng ta dưới

dạng một chuỗi các “hoạt động” rời rạc. Mỗi hoạt động có một tác nhân (thường là con người đang

sử dụng máy tính), một động từ (điều mà tác nhân đang làm) và một tân ngữ (điều mà tác nhân đang

thực hiện động từ).

Khi bạn xem một video trực tuyến, đó là một hoạt động. Bạn là diễn viên, video là đối tượng và

động từ (theo Luồng hoạt động) là chuỗi ký tự “chơi”. Một số hoạt động có mục tiêu cũng như đối

tượng. Khi tôi xuất bản một bài viết mới lên blog của mình, tôi là tác nhân, bài viết blog là đối

tượng, động từ là “bài đăng” và mục tiêu là blog của tôi.

Tôi đã đặt Luồng hoạt động trong phần này, mặc dù đó là định dạng dữ liệu vì định dạng dữ liệu

không xác định bất kỳ điều khiển siêu phương tiện nào. Nhưng có rất nhiều ngữ nghĩa thực sự hữu

ích ở đây. Luồng hoạt động xác định tên và mô tả ngữ nghĩa cho nhiều

234 | Chương 10: Sở thú Hypermedia


Machine Translated by Google

những thứ chúng ta tương tác trực tuyến (Bài viết, Sự kiện, Nhóm, Người). Quan trọng hơn, nó
xác định rất nhiều tên hữu ích cho các động từ (join, rsvp-yes, follow, cancel), có ý nghĩa
như tên của các chuyển đổi trạng thái không an toàn.

Tiêu chuẩn Luồng hoạt động giải thích cách trình bày một chuỗi các hoạt động dưới dạng nguồn cấp dữ liệu

Atom. Hãy sử dụng tính năng này và Luồng hoạt động sẽ là một định dạng siêu phương tiện thực sự, một phần
mở rộng cho Atom.

Ngoài ra còn có một phiên bản Luồng hoạt động dựa trên JSON độc lập. Nó có cùng các vấn đề như GeoJSON:

không có điều khiển siêu phương tiện và không có cách nào để phân biệt tài liệu Luồng hoạt động với tài liệu

JSON đơn giản.10 Để thêm điều khiển siêu phương tiện vào tài liệu Luồng hoạt động JSON, bạn sẽ cần sử dụng

JSON-LD hoặc Hydra (Chương 12).

Có nhiều điểm trùng lặp giữa ngữ nghĩa của Luồng hoạt động và các mục vi dữ liệu của Schema.org. Có các mục

vi dữ liệu được gọi là Bài viết, Sự kiện, Nhóm và Người. Mục vi dữ liệu Người dùng-Checkins giống như động

từ “checkin” của Luồng hoạt động, UserLikes giống như “like” và UserPlays giống như “play”. (Đối với bản

ghi, Luồng hoạt động có trước Schema.org.)

Cơ quan đăng ký ALPS Tôi đã

thiết lập cơ quan đăng ký hồ sơ ALPS tại trang này để tái sử dụng chung. Là một phần trong công việc của tôi

nhằm giải phóng ngữ nghĩa ứng dụng khỏi các loại phương tiện của chúng, tôi đã tạo các phiên bản ALPS của

các mục siêu dữ liệu Schema.org, một số vi định dạng và Dublin Core. Đó chỉ là sự khởi đầu; hy vọng vào thời

điểm bạn đọc bài viết này, tôi cũng sẽ tạo được các hồ sơ ALPS truyền tải được ngữ nghĩa ứng dụng của các

tiêu chuẩn khác.

Nếu muốn sử dụng cấu hình ALPS để xác định ngữ nghĩa ứng dụng API của mình, bạn có thể tìm kiếm trên Alps.io

để tìm cấu hình phù hợp với mình hoặc tập hợp một cấu hình mới từ các cấu hình hiện có.

Nếu bạn quyết định sử dụng cấu hình ALPS trong API của mình, vui lòng tham khảo các bit của cấu hình trong

Sổ đăng ký ALPS. Sau khi bạn hoàn tất, tôi sẽ đánh giá cao nếu bạn tải hồ sơ lên Cơ quan đăng ký ALPS (cũng

như lưu trữ hồ sơ cục bộ như một phần API của bạn). Bằng cách đó, người khác có thể tìm và sử dụng lại ngữ

nghĩa ứng dụng của bạn.

10. “Draft-snell-activity-streams-type” Internet-Draft sẽ giải quyết vấn đề thứ hai. Nó đăng ký phương tiện truyền thông

gõ application/stream+json cho tài liệu Luồng hoạt động.

Sở thú ngữ nghĩa | 235


Machine Translated by Google
Machine Translated by Google

CHƯƠNG 11
HTTP cho API

Hãy coi World Wide Web (và bất kỳ API RESTful nào khác) như một kho công nghệ.
URL ở dưới cùng; họ xác định tài nguyên. Giao thức HTTP nằm trên các tài nguyên đó, cung
cấp quyền truy cập đọc vào các biểu diễn của chúng và quyền truy cập ghi vào trạng thái
tài nguyên cơ bản. Hypermedia nằm trên HTTP, mô tả ngữ nghĩa giao thức của một trang
web hoặc API cụ thể.

Hình 11-1. Kho công nghệ hình thành nên World Wide Web

Lớp dưới cùng trả lời câu hỏi “Tài nguyên ở đâu?” Lớp giữa trả lời câu hỏi “Làm cách
nào để liên lạc với tài nguyên?” Lớp trên cùng trả lời câu hỏi “Tiếp theo là gì?”

Cho đến nay, cuốn sách này đã tập trung vào lớp trên cùng của ngăn xếp— “Tiếp theo là gì?” Đó là bởi vì

lớp trên cùng là lớp phức tạp nhất. Hầu hết các API ngày nay đều sử dụng URL và HTTP một cách chính xác

nhưng thậm chí không bận tâm đến hypermedia.

Trong chương này, tôi sẽ tạm dừng sử dụng hypermedia và đi xuống một cấp độ để giải
thích ngữ nghĩa giao thức nâng cao của HTTP. Tôi không muốn giải thích chi tiết về giao
thức HTTP; vì điều đó, tôi khuyên dùng HTTP: Hướng dẫn dứt khoát, của David Gourley và Brian

237
Machine Translated by Google

Totty (O'Reilly). Tôi sẽ tập trung vào các tính năng của HTTP đặc biệt hữu ích trong API và các tính

năng mà các nhà phát triển API mới có thể không biết đến.

Đặc tả HTTP/1.1 mới


Trong suốt cuốn sách này, tôi đã sử dụng “RFC 2616” làm cách viết tắt cho đặc tả HTTP 1.1. Nhưng Roy

Fielding (của luận án Fielding nổi tiếng) và một nhóm làm việc của IETF đang nghiên cứu một loạt RFC

thay thế sẽ khiến RFC 2616 trở nên lỗi thời.

Không có gì về giao thức HTTP sẽ thay đổi; vấn đề là cải thiện tài liệu. RFC mới làm rõ ngữ nghĩa giao

thức của HTTP và hợp nhất một số tiện ích bổ sung được xác định sau khi RFC 2616 được xuất bản, chẳng

hạn như định nghĩa của lược đồ https:// URI.

Hy vọng rằng các RFC mới đã được xuất bản vào thời điểm bạn đọc bài viết này. Nhưng nếu chúng vẫn đang

được thực hiện, bạn có thể đọc bản nháp bằng cách vào danh sách tài liệu của nhóm làm việc . Đó là một

cách dễ dàng hơn để hiểu một số phần phức tạp của giao thức HTTP hơn là nghiên cứu kỹ RFC 2616.

Mã phản hồi
RFC 2616 xác định 41 mã phản hồi HTTP. Một số trong số chúng không hữu ích cho mục đích của chúng tôi,

nhưng nhìn chung, chúng đại diện cho một tập hợp ngữ nghĩa cơ bản, được xác định theo tiêu chuẩn cơ bản

nhất trong tất cả các tiêu chuẩn API. Không có lý do gì để bỏ qua món quà này. Nếu bạn phát minh lại

404 (Không tìm thấy) hoặc 409 (Xung đột) cho API của mình thì bạn chỉ đang tạo thêm công việc cho mọi người.

Sử dụng mã phản hồi của bạn.

Nếu khách hàng gửi một số dữ liệu không hợp lệ tới API của bạn, bạn nên gửi mã phản hồi 400 (Yêu cầu

không hợp lệ) và nội dung thực thể giải thích vấn đề là gì. Đừng gửi 200 (OK) kèm theo thông báo lỗi.

Bạn đang nói dối khách hàng. Bạn sẽ phải viết thêm tài liệu giải thích rằng trong API của mình, OK đôi

khi không có nghĩa là “OK”.

Trong Phụ lục A, tôi nói về tất cả các mã phản hồi được xác định trong tiêu chuẩn HTTP và một số mã hữu

ích khác được xác định trong các RFC bổ sung.

Tiêu đề
RFC 2616 xác định 47 tiêu đề phản hồi và yêu cầu HTTP. Giống như mã phản hồi, một số mã gần như vô dụng

nhưng nhìn chung chúng xác định một tập hợp ngữ nghĩa cơ bản mà mọi API đều có thể hưởng lợi. Sử dụng
chúng.

Một số tiêu đề tương ứng với các tính năng của HTTP quan trọng đối với API: đáng chú ý là đàm phán nội

dung và yêu cầu có điều kiện. Tôi đã đưa ra những phần riêng của chúng trong chương này. Trong Phụ lục

B, tôi nói về tất cả các tiêu đề được xác định theo tiêu chuẩn HTTP.

238 | Chương 11: HTTP cho API


Machine Translated by Google

Tôi cũng đề cập đến một số tiện ích mở rộng hữu ích: đáng chú ý là tiêu đề Liên kết mà bạn đã thấy.

Lựa chọn giữa các đại diện


Một tài nguyên có thể có nhiều cách biểu diễn. Thông thường, các biểu diễn ở các định dạng dữ liệu khác

nhau: nhiều API web phục vụ “các hương vị” XML và JSON cho tất cả các tài nguyên của chúng. Đôi khi các

cách trình bày chứa đựng văn xuôi đã được dịch sang các ngôn ngữ khác nhau của con người. Đôi khi các

cách biểu diễn khác nhau biểu thị các bit khác nhau của trạng thái tài nguyên: một tài nguyên có thể có

“biểu diễn tổng quan” và “biểu diễn chi tiết”.

Khi máy chủ cung cấp nhiều cách biểu diễn cho một tài nguyên, máy khách phải làm cách nào để phân biệt

giữa chúng? Làm thế nào để khách hàng báo hiệu họ muốn tiếng Anh hay tiếng Tây Ban Nha, XML hay JSON,

tổng quan hay chi tiết? Có hai chiến lược chính.

Đàm phán nội dung Máy khách

có thể sử dụng các tiêu đề yêu cầu HTTP đặc biệt để cho máy chủ biết nó muốn thể hiện những gì. Quá

trình này được gọi là đàm phán nội dung và tiêu chuẩn HTTP xác định năm tiêu đề yêu cầu cho nó. Chúng

được gọi chung là các tiêu đề Accept-* . Tôi sẽ đề cập đến cả năm điều trong Phụ lục B, nhưng ở đây tôi

muốn nhấn mạnh hai điều quan trọng nhất: Ngôn ngữ chấp nhận và Ngôn ngữ chấp nhận.

Hầu hết các ứng dụng khách API web chỉ hiểu một loại phương tiện duy nhất. Khi họ đưa ra yêu cầu, họ sẽ

gửi tiêu đề Chấp nhận đơn giản , yêu cầu loại phương tiện đó:

Chấp nhận: application/vnd.collection+json

Máy khách thông báo cho máy chủ rằng nó chỉ hiểu Collection+JSON. Nếu máy chủ có tùy chọn phân phát

Atom hoặc Collection+JSON, thì máy chủ đó sẽ phân phối Collection+JSON.

Khi tôi thực hiện một yêu cầu HTTP từ trình duyệt web của mình, nó sẽ gửi một yêu cầu phức tạp hơn nhiều

Chấp nhận tiêu đề:

Chấp nhận: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

RFC 2616 cung cấp thông tin chi tiết phức tạp về những gì có thể đưa vào tiêu đề Accept-* , nhưng ví dụ

thực tế này đóng vai trò là một chỉ báo tốt về những gì có thể làm được. Công việc chính của trình

duyệt web là hiển thị các trang web, vì vậy trình duyệt của tôi ưu tiên hàng đầu cho các biểu diễn HTML

(loại phương tiện văn bản/html ) và các biểu diễn XHTML (ứng dụng/xhtml). Trình duyệt của tôi cũng có

thể hiển thị XML thô (ứng dụng/xml), nhưng vì nó trông không đẹp bằng nên XML được ưu tiên thấp hơn HTML

(q=0,9). Nếu không có biểu diễn HTML hay XML nào (có thể vì tài nguyên là hình ảnh nhị phân), trình

duyệt của tôi sẽ chấp nhận bất kỳ loại phương tiện nào (*/*). Nhưng đó là lựa chọn cuối cùng và được ưu

tiên thấp nhất (q=0,8).

Lựa chọn giữa các đại diện | 239


Machine Translated by Google

Trình duyệt web của tôi cũng có cài đặt cho tùy chọn ngôn ngữ: ngôn ngữ nào tôi muốn sử dụng để truy cập các trang

web. Với mỗi yêu cầu HTTP tôi thực hiện, trình duyệt của tôi sẽ chuyển đổi tùy chọn ngôn ngữ của tôi thành giá trị

cho tiêu đề Ngôn ngữ chấp nhận :

Ngôn ngữ chấp nhận: en-us,en;q=0.5

Điều này nói lên rằng tôi thích tiếng Anh Mỹ hơn, nhưng tôi sẽ chấp nhận bất kỳ phương ngữ nào của tiếng Anh như

một sự thay thế tốt thứ hai. (Tôi thực sự không kén chọn về vấn đề này, nhưng đó là những gì tôi đã nói với trình

duyệt web của mình.)

Nếu máy chủ không thể thực hiện yêu cầu do hạn chế Accept-* , nó có thể gửi mã phản hồi 406 (Không được chấp nhận).

Đàm phán một hồ sơ Trong

Chương 8, tôi đã loại bỏ tham số loại phương tiện hồ sơ vì không có nhiều loại phương tiện hỗ trợ nó, nhưng nó có

lợi thế lớn trong việc đàm phán nội dung. Khi loại phương tiện hỗ trợ tham số cấu hình , bạn có thể sử dụng thương

lượng nội dung để yêu cầu một cấu hình cụ thể. Đây là một khách hàng muốn có bản trình bày XHTML sử dụng vi định

dạng hCard:

Chấp nhận: application/xml+xhtml;profile="http://microformats.org/wiki/hcard"

Khách hàng này muốn có cùng định dạng dữ liệu (XHTML) nhưng muốn dữ liệu được trình bày dưới dạng vi dữ liệu

Schema.org:

Chấp nhận: application/xml+xhtml;profile="http://schema.org/Person"

Bạn không thể làm điều đó nếu hồ sơ được truyền tải thông qua tiêu đề Liên kết . Và tất nhiên, bạn không thể làm

điều đó nếu loại phương tiện không hỗ trợ tham số profile .

Menu Hypermedia Đó là đàm phán

nội dung. Nhưng hãy xem xét cách khách hàng tìm thấy sự đại diện mà họ muốn nói chung. Không có quá trình “thương

lượng tài nguyên”. Thay vào đó, máy khách thực hiện yêu cầu GET tới URL biển quảng cáo của API và máy chủ phân

phát bản trình bày trang chủ bao gồm các liên kết hypermedia đến các tài nguyên khác. Máy khách chọn liên kết nào

nó muốn theo dõi và thực hiện một yêu cầu GET khác cho một đại diện khác. Máy khách tìm thấy tài nguyên mà nó đang

tìm kiếm bằng cách lần lượt đưa ra các lựa chọn.

Chiến lược này cũng hoạt động tốt khi các lựa chọn là sự lựa chọn giữa các định dạng dữ liệu.

Các tính năng đàm phán nội dung của HTTP chỉ tối ưu hóa cho một số trường hợp phổ biến. Thay vì sử dụng chúng,

bạn có thể cung cấp cho mỗi phần trình bày URL riêng, biến nó thành một tài nguyên độc lập một cách hiệu quả.

Máy chủ đưa ra lựa chọn giữa các tài nguyên này bằng cách gửi mã phản hồi 300 (Nhiều lựa chọn). Phần thân thực

thể phải chứa một tài liệu hypermedia liên kết với các lựa chọn khác nhau. Nếu bạn làm theo cách này, bạn sẽ cần

sử dụng định dạng hypermedia

240 | Chương 11: HTTP cho API


Machine Translated by Google

có khả năng giải thích những gì ở đầu bên kia của một liên kết. Nếu không, khách hàng của bạn

sẽ không có cách nào quyết định nên nhấp vào liên kết nào.

Các thẻ <a> và <link> của HTML hỗ trợ tốt cho việc này, với thuộc tính type :

<a href="/resource/siren" type="application/vnd.siren+json" rel="alternate"> Phiên bản


Siren. </a>

<a href="/resource/html" type="text/html" rel="alternate">


Phiên bản HTML. </a>

Thuộc tính hreflang là gợi ý về ngôn ngữ ở đầu bên kia của liên kết:

<a href="/resource.es" hreflang="es"> Đối


với phiên bản tiếng Tây Ban Nha, hãy nhấp vào đây.
</a>

Vì hầu hết các định dạng hypermedia không có những tính năng này nên tôi thường khuyên bạn nên

đàm phán nội dung dựa trên tiêu đề cho việc này.

URL chuẩn
Bất cứ khi nào một tài nguyên có nhiều URL, bạn nên xác định một trong số chúng là URL chính

thức hoặc URL chuẩn: URL mà khách hàng nên sử dụng khi nói về tài nguyên thay vì gửi yêu cầu

HTTP tới tài nguyên đó.

Có hai cách để làm điều này. Trước tiên, bạn có thể sử dụng tiêu đề HTTP Content-Location tiêu

chuẩn làm điều khiển siêu phương tiện trỏ đến URL chuẩn của tài nguyên hiện tại.

Ngoài ra còn có chuẩn quan hệ liên kết đã đăng ký IANA , phục vụ cùng mục đích. Bạn có thể sử

dụng chuẩn trong phần trình bày hoặc trong tiêu đề Liên kết .

Hiệu suất HTTP


Máy khách HTTP được phép thực hiện bất kỳ yêu cầu HTTP nào họ muốn, bất cứ khi nào họ muốn.
Nhưng một số yêu cầu hóa ra lại là sự lãng phí thời gian vô nghĩa. HTTP xác định một số cách

tối ưu hóa để ngăn chặn các yêu cầu có khả năng vô nghĩa (lưu vào bộ nhớ đệm), để giảm chi phí

của một yêu cầu hóa ra là vô nghĩa (yêu cầu có điều kiện) và để giảm chi phí của một yêu cầu

nói chung (nén).

Bộ nhớ đệm

Bộ nhớ đệm là một trong những phần phức tạp nhất của HTTP. RFC 2616 chứa các quy tắc chi tiết

về việc vô hiệu hóa bộ đệm và có nhiều vấn đề liên quan đến các trung gian HTTP như proxy bộ

đệm. Tôi sẽ tập trung vào cách đơn giản nhất để thêm bộ đệm vào API web, sử dụng Kiểm soát bộ

đệm tiêu đề HTTP. Trong Phụ lục B, tôi cũng sẽ thảo luận về tiêu đề Hết hạn , tiêu đề này rất

hữu ích trong một trường hợp phổ biến khác. Đối với bất cứ điều gì phức tạp hơn, tôi sẽ

Hiệu suất HTTP | 241


Machine Translated by Google

giới thiệu bạn đến HTTP: Hướng dẫn dứt khoát, và tới “draft-ietf-httpbis-p6-cache” Internet-Draft, một

phần trong nỗ lực hiện tại nhằm thay thế RFC 2616.

Đây là tiêu đề Kiểm soát bộ đệm đang hoạt động, như một phần của phản hồi cho yêu cầu HTTP GET:

HTTP/1.1 200 OK
Loại nội dung: text/html Kiểm
soát bộ đệm: max-age=3600
...

Lệnh max-age cho biết khách hàng phải đợi bao lâu trước khi thực hiện lại yêu cầu HTTP này. Nếu khách hàng

nhận được phản hồi này và nửa giờ sau, khách hàng muốn gửi lại yêu cầu thì khách hàng sẽ tạm dừng. Máy

chủ cho biết sẽ kiểm tra lại sau một giờ (3.600 giây) chứ không phải trước đó.

Chỉ thị bộ nhớ đệm áp dụng cho toàn bộ phản hồi HTTP, bao gồm tiêu đề và mã phản hồi, không chỉ cho phần

nội dung thực thể. Ý tưởng là nếu máy khách thực sự cần xem phản hồi HTTP, thì máy khách sẽ xem xét phản

hồi được lưu trong bộ nhớ đệm thay vì thực hiện lại yêu cầu.

Một cách sử dụng phổ biến khác của Kiểm soát bộ đệm là để máy chủ yêu cầu máy khách không lưu phản hồi

vào bộ nhớ đệm, ngay cả khi điều đó làm ngược lại:

HTTP/1.1 200 OK
Loại nội dung: text/html Kiểm
soát bộ đệm: không có bộ đệm
...

Điều này chỉ ra rằng trạng thái tài nguyên không ổn định đến mức việc thể hiện có thể trở nên lỗi thời

trong thời gian gửi nó.

Việc đặt Kiểm soát bộ đệm khi bạn phục vụ một đại diện yêu cầu bạn đưa ra phán quyết về tần suất một đại

diện sẽ thay đổi. Nếu bạn hiểu sai điều này, điều này có thể dẫn đến việc dữ liệu của người dùng đã lỗi

thời.

Đối với các biểu diễn bao gồm hoàn toàn các điều khiển hypermedia, các biểu diễn chỉ thay đổi khi bạn

nâng cấp triển khai API của mình, việc đặt tuổi tối đa khá cao là điều hợp lý. Hoặc bạn có thể sử dụng…

NHẬN có điều kiện

Đôi khi bạn không biết khi nào trạng thái của tài nguyên sẽ thay đổi. (Tài nguyên loại bộ sưu tập là tệ

nhất đối với việc này.) Nó có thể thay đổi mọi lúc hoặc có thể thay đổi hiếm khi đến mức bạn không thể

ước tính tần suất thay đổi xảy ra. Dù bằng cách nào, bạn không thể quyết định giá trị cho độ tuổi tối đa,

vì vậy bạn không thể yêu cầu khách hàng ngừng yêu cầu tài nguyên đó trong một thời gian. Thay vào đó, bạn

có thể để máy khách đưa ra yêu cầu bất cứ khi nào nó muốn và loại bỏ phản hồi của máy chủ nếu không có gì

thay đổi.

242 | Chương 11: HTTP cho API


Machine Translated by Google

Tính năng phía máy khách này được gọi là yêu cầu có điều kiện và để hỗ trợ nó, bạn sẽ cần phân

phát tiêu đề Last-Modified hoặc ETag cùng với phần trình bày của mình (tốt hơn hết là phân phát cả

hai). Tiêu đề được sửa đổi lần cuối cho khách hàng biết thời điểm trạng thái của tài nguyên này

thay đổi lần cuối. Đây là một ví dụ về phản hồi HTTP:

HTTP/1.1 200 OK Độ
dài nội dung: 41123 Loại
nội dung: text/html Sửa đổi
lần cuối: Thứ Hai, ngày 21 tháng 1 năm 2013 09:35:19 GMT

<html>
...

Máy khách ghi lại giá trị được sửa đổi lần cuối và lần sau khi thực hiện yêu cầu, nó sẽ đặt giá

trị đó vào tiêu đề HTTP If-Modified-Since:

GET /some-resource HTTP/1.1 If-


Modified-Since: Thứ Hai, ngày 21 tháng 1 năm 2013 09:35:19 GMT

Nếu trạng thái tài nguyên đã thay đổi kể từ ngày được cung cấp trong If-Modified-Since thì không có

gì đặc biệt xảy ra. Máy chủ gửi mã trạng thái 200, Bản sửa đổi lần cuối được cập nhật và bản

trình bày đầy đủ:

HTTP/1.1 200 OK Độ
dài nội dung: 44181 Loại
nội dung: text/html Sửa đổi
lần cuối: Thứ Hai, ngày 27 tháng 1 năm 2013 07:57:10 GMT

<html>
...

Nhưng nếu phần trình bày không thay đổi kể từ yêu cầu cuối cùng thì máy chủ sẽ gửi mã trạng thái

304 (Không được sửa đổi) và không có nội dung thực thể:

HTTP/1.1 304 Không được sửa đổi


Độ dài nội dung: 0 Sửa
đổi lần cuối: Thứ Hai, ngày 27 tháng 1 năm 2013 07:57:10 GMT

Điều này giúp tiết kiệm thời gian và băng thông của cả hai bên. Máy chủ không phải gửi đại diện và

máy khách không cần phải nhận nó. Nếu bản trình bày được tạo động từ trạng thái tài nguyên thì yêu

cầu có điều kiện cũng giúp máy chủ tiết kiệm công sức tạo bản trình bày.

Tất nhiên, điều này có nghĩa là bạn sẽ phải làm thêm việc. Bạn sẽ cần theo dõi ngày sửa đổi gần

đây nhất của tất cả tài nguyên của mình. Và hãy nhớ rằng giá trị của Last-Modified là ngày biểu

diễn được thay đổi. Nếu bạn có một tài nguyên bộ sưu tập mà biểu diễn của nó bao gồm các bit của

các biểu diễn khác, thì Bản sửa đổi lần cuối của tài nguyên đó biểu thị lần cuối cùng bất kỳ nội

dung nào trong số đó được thay đổi.

Hiệu suất HTTP | 243


Machine Translated by Google

Có một chiến lược khác dễ thực hiện hơn Last-Modified và tránh được một số điều kiện chạy đua.

Tiêu đề ETag (viết tắt của “thẻ thực thể”) chứa một chuỗi vô nghĩa phải thay đổi bất cứ khi nào

biểu diễn tương ứng thay đổi.

Dưới đây là một phản hồi HTTP mẫu bao gồm ETag:

HTTP/1.1 200 OK
Độ dài nội dung: 44181
Loại nội dung: text/html
ETag: "7359b7-a37c-45b333d7"

<html>
...

Khi máy khách thực hiện yêu cầu thứ hai cho cùng một tài nguyên, nó sẽ đặt giá trị If-None-

So khớp tiêu đề với ETag mà nó nhận được trong phản hồi ban đầu:

NHẬN/một số tài nguyên HTTP/1.1


Nếu không khớp: "7359b7-a37c-45b333d7"

Nếu ETag trong If-None-Match giống với ETag hiện tại của biểu diễn, máy chủ sẽ gửi 304 (Không được

sửa đổi) và phần nội dung thực thể trống. Nếu biểu diễn đã thay đổi, máy chủ sẽ gửi 200 (OK), nội

dung thực thể đầy đủ và ETag được cập nhật.

Việc cung cấp Sửa đổi lần cuối yêu cầu bạn phải theo dõi nhiều dấu thời gian, nhưng bạn có thể

tạo Thẻ ET cho các biểu diễn mà không cần theo dõi bất kỳ dữ liệu bổ sung nào. Một phép biến đổi

như hàm băm MD5 có thể biến bất kỳ chuỗi byte nào thành một chuỗi ngắn duy nhất đáng tin cậy.

Vấn đề là vào thời điểm bạn có thể chạy một trong những phép biến đổi đó, bạn đã tạo biểu diễn

dưới dạng một chuỗi byte. Cuối cùng, bạn có thể tiết kiệm băng thông bằng cách không gửi biểu diễn

qua đường dây, nhưng bạn đã hoàn thành công việc cần thiết để xây dựng nó. Việc sử dụng ETag để

tiết kiệm thời gian, thay vì băng thông, yêu cầu bạn lưu vào bộ đệm ETag của một biểu diễn và vô

hiệu hóa bộ nhớ đệm khi biểu diễn thay đổi.

Last -Modified hoặc ETag sẽ cung cấp cho bạn sự hỗ trợ cho các yêu cầu có điều kiện, nhưng việc

phục vụ cả hai sẽ là lý tưởng và ETag đáng tin cậy hơn Last-Modified.

Yêu cầu Xem trước khi bạn nhảy GET có điều

kiện được thiết kế để ngăn máy chủ gửi các đại diện khổng lồ đến máy khách đã có chúng. Một tính

năng khác của HTTP, ít được sử dụng hơn, có thể giúp máy khách không phải gửi các đại diện khổng

lồ (hoặc nhạy cảm) đến máy chủ một cách vô ích.

Không có tên chính thức cho loại yêu cầu này, vì vậy Dịch vụ web RESTful ban đầu đã giới thiệu

một cái tên ngớ ngẩn—yêu cầu xem trước khi nhảy—dường như đã bị mắc kẹt.

244 | Chương 11: HTTP cho API


Machine Translated by Google

Để thực hiện yêu cầu LBYL, khách hàng sẽ gửi yêu cầu không an toàn, chẳng hạn như PUT, bỏ qua nội

dung thực thể. Máy khách đặt tiêu đề yêu cầu Expect thành chuỗi ký tự 100- continue. Đây là một yêu

cầu LBYL mẫu:

PUT /filestore/myfile.txt HTTP/1.1 Máy


chủ: example.com Độ
dài nội dung: 524288000 Dự
kiến: 100-tiếp tục

Đây không phải là một yêu cầu PUT thực sự: đó là câu hỏi về một yêu cầu PUT có thể xảy ra trong tương

lai. Máy khách đang hỏi máy chủ: “bạn có cho phép tôi ĐƯA một bản trình bày mới vào /filestore/

myfile.txt không? Máy chủ đưa ra quyết định dựa trên trạng thái hiện tại của tài nguyên đó và các

tiêu đề HTTP do máy khách cung cấp. Trong trường hợp này, máy chủ sẽ kiểm tra Độ dài nội dung và

quyết định xem nó có sẵn sàng chấp nhận tệp 500 MB hay không.

Nếu câu trả lời là có, máy chủ sẽ gửi mã trạng thái 100 (Tiếp tục). Sau đó, khách hàng dự kiến sẽ

gửi lại yêu cầu PUT, bỏ qua Kỳ vọng và bao gồm phần trình bày 500 MB trong phần nội dung thực thể.

Máy chủ đã đồng ý chấp nhận đại diện đó.

Nếu câu trả lời là không, máy chủ sẽ gửi mã trạng thái 417 (Không đạt kỳ vọng). Câu trả lời có thể

là không vì tài nguyên tại /filestore/myfile.txt được bảo vệ chống ghi, vì khách hàng không cung cấp

thông tin xác thực phù hợp hoặc vì 500 MB là quá lớn. Dù lý do là gì đi nữa, yêu cầu xem trước khi

nhảy ban đầu đã giúp khách hàng không phải gửi 500 MB dữ liệu để rồi bị từ chối dữ liệu đó. Cả máy

khách và máy chủ đều tốt hơn.

Tất nhiên, một khách hàng có phần trình bày không tốt có thể nói dối về điều đó trong các tiêu đề chỉ

để nhận được mã trạng thái là 100, nhưng điều đó sẽ chẳng mang lại lợi ích gì. Máy chủ sẽ không chấp

nhận nội dung trình bày không hợp lệ trong yêu cầu thứ hai, nhiều hơn những gì nó có trong yêu cầu

đầu tiên. Quá trình tải lên lớn của khách hàng có thể sẽ bị gián đoạn bởi mã phản hồi 413 (Thực thể

yêu cầu quá lớn).

Nén Các biểu diễn

văn bản như tài liệu JSON và XML có thể được nén thành một phần kích thước ban đầu của chúng. Thư

viện máy khách HTTP có thể yêu cầu phiên bản nén của biểu diễn và sau đó giải nén nó một cách minh

bạch cho người dùng.

Đây là cách nó hoạt động. Khi máy khách gửi yêu cầu, nó sẽ bao gồm tiêu đề Accept-Encoding cho biết

thuật toán nén nào máy khách hiểu được. IANA lưu giữ sổ đăng ký các giá trị được chấp nhận tại trang

IANA này (đó là danh sách “mã hóa nội dung”), nhưng giá trị bạn muốn sử dụng là gzip:

NHẬN /resource.html Máy chủ HTTP/


1.1: www.example.com Mã
hóa chấp nhận: gzip

Hiệu suất HTTP | 245


Machine Translated by Google

Nếu máy chủ hiểu một trong các thuật toán nén được đề cập trong Mã hóa chấp nhận, nó có thể

sử dụng thuật toán đó để nén biểu diễn trước khi phân phát.

Máy chủ gửi cùng một Loại nội dung mà nó sẽ gửi nếu phần trình bày không được nén. Nhưng nó

cũng gửi tiêu đề Mã hóa nội dung để khách hàng biết tài liệu đã được nén:

HTTP/1.1 200 OK
Loại nội dung: text/html Mã
hóa nội dung: gzip

[Biểu diễn nhị phân ở đây.]

Máy khách giải nén dữ liệu bằng thuật toán được cung cấp trong Mã hóa nội dung, sau đó coi dữ

liệu đó là loại phương tiện được cung cấp dưới dạng Loại nội dung. Trong trường hợp này, máy

khách sẽ sử dụng thuật toán gzip để giải nén dữ liệu nhị phân trở lại tài liệu HTML. Đối với

khách hàng, nó đã yêu cầu HTML và nó nhận được HTML. Kỹ thuật này có thể tiết kiệm rất nhiều

băng thông với chi phí rất thấp và độ phức tạp tăng thêm.

NHẬN một phần

HTTP một phần GET cho phép máy khách chỉ tìm nạp một tập hợp con của biểu diễn. Nó thường được
sử dụng để tiếp tục tải xuống bị gián đoạn. Hầu hết các máy chủ web đều hỗ trợ GET một phần cho

nội dung tĩnh. Nếu API của bạn phục vụ các tệp tĩnh lớn thì bạn nên nỗ lực hỗ trợ GET một phần
trên chúng.

Tài nguyên hỗ trợ GET một phần sẽ quảng cáo thực tế này để phản hồi GET thông thường, bằng cách

đặt tiêu đề phản hồi Phạm vi chấp nhận thành byte chuỗi ký tự . Đây là phản hồi cho yêu cầu GET

thành công đối với một tệp video rất lớn:

HTTP/1.1 200 OK Độ
dài nội dung: 1271174395 Phạm vi
chấp nhận: byte Loại nội
dung: video/mpeg

[Biểu diễn nhị phân ở đây.]

Nếu quá trình tải xuống bị gián đoạn, máy khách hỗ trợ GET một phần có thể tiếp tục tải xuống

từ điểm bị gián đoạn, thay vì bắt đầu lại. Đây là yêu cầu cho kilobyte cuối cùng của tệp video

đó:

NHẬN /tệp video lớn


Phạm vi: 1271173371-

Phản hồi sẽ như thế này:

206 Nội dung một phần-

Loại nội dung: video/mpeg


Phạm vi nội dung: 1271173371-1271174395
Độ dài nội dung: 1024

246 | Chương 11: HTTP cho API


Machine Translated by Google

[Biểu diễn nhị phân ở đây.]

Về lý thuyết, GET một phần có thể được sử dụng để chia một biểu diễn không thành các đoạn byte mà

thành các phần logic . Trong thế giới giả tưởng này, tiêu đề Phạm vi chấp nhận sẽ có giá trị khác

ngoài byte và tiêu đề Phạm vi sẽ được sử dụng để truy xuất, giả sử, các mục từ 2 đến 5 của bộ sưu

tập.

Đây là một ý tưởng hay, nhưng không có tiêu chuẩn nào trong lĩnh vực này và tôi thường phản đối

việc tạo ra ngữ nghĩa giao thức của riêng bạn. Nếu bạn muốn chia nhỏ một bộ sưu tập để có được một

số yêu cầu HTTP để có được toàn bộ nội dung, bạn nên tạo một số tài nguyên “trang” và liên kết các

phần trình bày của chúng với nhau bằng cách sử dụng các mối quan hệ liên kết đã đăng ký IANA như

next và previous .

Pipeline

Pipeline giảm độ trễ bằng cách cho phép máy khách gửi nhiều yêu cầu HTTP cùng một lúc.

Máy chủ gửi lại phản hồi từ máy chủ theo thứ tự nhận được yêu cầu.

Đường ống phụ thuộc vào, nhưng khác với các kết nối liên tục, một tính năng của HTTP cho phép khách

hàng gửi một số yêu cầu qua một kết nối TCP.

Máy khách có thể dẫn bất kỳ chuỗi yêu cầu HTTP bình thường nào, miễn là toàn bộ chuỗi đó cũng bình

thường. Nếu kết nối bị gián đoạn, bạn phải có khả năng phát lại toàn bộ loạt phim và nhận được kết

quả tương tự.

Đây là một ví dụ đơn giản. Tôi sẽ gửi hai yêu cầu qua một đường dẫn. Đầu tiên tôi sẽ truy xuất bản

trình bày của một tài nguyên và sau đó tôi sẽ xóa tài nguyên đó:

NHẬN /tài nguyên


XÓA/tài nguyên

GET và DELETE là bình thường, nhưng sự kết hợp của chúng thì không. Nếu xảy ra sự cố mạng sau khi

tôi gửi những yêu cầu này và tôi không nhận được phản hồi đầu tiên trong quy trình, thì tôi sẽ

không thể gửi lại yêu cầu và nhận được kết quả tương tự. Tài nguyên sẽ không còn ở đó nữa. Do sự

phức tạp này, tôi chỉ khuyên bạn nên tạo đường dẫn cho các chuỗi yêu cầu GET.

Ngoài sự phức tạp đó, việc tạo đường ống thường xuyên không giúp ích gì cho hiệu suất. Pipeline chỉ

mang lại hiệu quả nếu khách hàng thực hiện một loạt yêu cầu HTTP dài tới cùng một tên miền và hầu
hết các trang web đều bao gồm các thành phần từ các tên miền khác nhau.

Các máy khách API không phải trình duyệt có xu hướng thực hiện một loạt yêu cầu dài tới một miền

duy nhất, nhưng việc tạo đường ống cũng không thực sự hữu ích đối với các API dựa trên hypermedia

vì API hypermedia thường yêu cầu máy khách kiểm tra phản hồi cho một yêu cầu trước khi thực hiện

một yêu cầu khác. . Có lẽ đó là lý do tại sao hầu hết các thư viện máy khách HTTP có thể lập trình

cũng không hỗ trợ đường ống.

Hiệu suất HTTP | 247


Machine Translated by Google

Về cơ bản, tính năng này giống như một sự phá sản. Giao thức HTTP 2.0 (được đề cập trong phần cuối của chương

này) sẽ triển khai đường dẫn HTTP theo cách hữu ích hơn. Như vậy, việc tạo đường ống có thể hữu ích cho một ứng

dụng khách như người tạo bản đồ của Chương 5 hoặc một ứng dụng khách chạy trên thiết bị di động có độ trễ cao.

Đây không phải là điều bắt buộc phải có như GET có điều kiện, nhưng khi bạn đang nghĩ đến việc cải thiện hiệu

suất, thì việc tạo đường dẫn rất đáng để xem xét. Tuy nhiên, đó là khuyến nghị cao nhất mà tôi có thể đưa ra.

Tránh sự cố cập nhật bị mất


Tôi đã giới thiệu ETag và Last-Modified như một cách tiết kiệm thời gian và băng thông khi thực hiện các yêu cầu

GET. Nhưng các yêu cầu có điều kiện cũng hữu ích như một cách tránh mất dữ liệu khi sử dụng các phương thức HTTP

không an toàn như PUT và PATCH.

Giả sử Alice và Bob đang sử dụng các ứng dụng khách API khác nhau để chỉnh sửa danh sách tạp hóa. Họ bắt đầu bằng

cách thực hiện các yêu cầu HTTP giống hệt nhau:

NHẬN /cửa hàng tạp hóa HTTP/


1.1 Máy chủ: www.example.com

Và lấy các biểu diễn giống hệt nhau:

HTTP/1.1 200 OK
Loại nội dung: text/plain ETag:
"7359b7-a37c-45b333d7"
Sửa đổi lần cuối: Thứ Hai, ngày 27 tháng 1 năm 2013 07:57:10 GMT

mì ống

dưa cải bắp

bánh mì tròn

Alice thêm một mục vào danh sách và PUT quay lại biểu diễn mới:

PUT /cửa hàng tạp hóa HTTP/


1.1 Máy chủ: www.example.com
Loại nội dung: text/plain

mì ống

dưa cải bắp

bánh mì tròn

Trứng

Cô ấy nhận được phản hồi là 200 (OK).

Bob, không biết Alice đang làm gì, thêm một mục vào danh sách và PUT trả lại cách trình bày mới của anh ấy :

PUT /cửa hàng tạp hóa HTTP/


1.1 Máy chủ: www.example.com
Loại nội dung: text/plain

mì ống

248 | Chương 11: HTTP cho API


Machine Translated by Google

dưa cải bắp

bánh mì tròn

Sữa

Bob cũng nhận được phản hồi là 200 (OK). Nhưng phiên bản danh sách của Alice—phiên bản bao gồm
“Trứng”—đã bị thất lạc. Bob thậm chí còn chưa bao giờ biết về phiên bản đó.

Loại bi kịch này có thể tránh được bằng cách đưa ra các yêu cầu không an toàn có điều kiện.
Với GET có điều kiện, chúng tôi muốn yêu cầu chỉ được thực hiện nếu cách biểu diễn đã thay
đổi. Ở đây, Bob muốn yêu cầu PUT của mình chỉ được thực hiện nếu cách trình bày không thay

đổi. Kỹ thuật giống nhau nhưng điều kiện bị đảo ngược. Thay vì If-Match, máy khách sử dụng

tiêu đề ngược lại, If-None-Match. Thay vì If-Modified-Since, máy khách sử dụng If-Unmodified-
Since.

Giả sử Bob đã đưa ra yêu cầu PUT có điều kiện:

PUT /cửa hàng tạp hóa HTTP/


1.1 Máy chủ:
www.example.com Loại nội
dung: text/plain If-Match: "7359b7-a37c-45b333d7"
Nếu-Chưa sửa đổi-Kể từ: Thứ Hai, ngày 27 tháng 1 năm 2013 07:57:10 GMT

mì ống

dưa cải bắp

bánh mì tròn

Sữa

Thay vì 200 (OK), máy chủ sẽ gửi mã trạng thái 412 (Điều kiện tiên quyết không thành công).

Khi đó khách hàng của Bob sẽ biết rằng ai đó đã sửa đổi danh sách hàng tạp hóa.
Thay vì ghi đè lên bản trình bày hiện tại, máy khách của Bob có thể gửi yêu cầu GET cho bản
trình bày mới và cố gắng hợp nhất nó với phiên bản của Bob. Hoặc nó có thể leo thang vấn đề và
yêu cầu Bob tự mình giải quyết. Nó phụ thuộc vào loại phương tiện truyền thông và ứng dụng.

Theo tôi, việc triển khai API của bạn phải yêu cầu khách hàng thực hiện các yêu cầu PUT và
PATCH có điều kiện. Nếu khách hàng cố gắng thực hiện PUT hoặc PATCH vô điều kiện, bạn nên gửi

mã trạng thái 428 (Yêu cầu điều kiện tiên quyết).

Xác thực
Để đơn giản, các ví dụ tôi trình bày xuyên suốt cuốn sách này không yêu cầu bất kỳ hình thức
xác thực nào. Bạn thực hiện một yêu cầu HTTP và nhận được phản hồi. Có rất nhiều API thực sự
như thế này, nhưng hầu hết các API đều yêu cầu xác thực.

Có hai bước để xác thực. Bước 1 là bước một lần trong đó người dùng thiết lập thông tin xác

thực của mình với nhà cung cấp dịch vụ. Thông thường, điều này có nghĩa là một người sử dụng
trình duyệt web của mình để tạo tài khoản trên máy chủ API hoặc liên kết một số tài khoản
người dùng hiện có trên một trang web với máy chủ API.

Xác thực | 249


Machine Translated by Google

Bước 2 là trình bày tự động thông tin xác thực của người dùng cùng với từng yêu cầu tới API.

Tại sao phải trình bày thông tin xác thực của người dùng cùng với mọi yêu cầu HTTP? Do ràng buộc không

trạng thái, cho phép máy chủ hoàn toàn quên đi ứng dụng khách giữa các yêu cầu. Không có phiên nào trong

quá trình triển khai máy chủ RESTful.1 Một số kỹ thuật xác thực cũng bao gồm “bước

0” được gọi là đăng ký. Tại đây, nhà phát triển sử dụng trình duyệt web của mình để thiết lập thông tin

xác thực cho ứng dụng khách phần mềm mà cô ấy đang viết.

Nếu một nghìn người sử dụng ứng dụng khách đó thì mỗi người sẽ phải thiết lập thông tin xác thực người

dùng cá nhân của riêng mình (bước 1), nhưng tất cả họ sẽ chia sẻ một bộ thông tin xác thực ứng dụng

khách. Khi API áp dụng kỹ thuật này, ứng dụng khách muốn thực hiện yêu cầu HTTP phải xuất trình cả thông
tin xác thực ứng dụng khách và bộ thông tin xác thực người dùng.

Tiêu đề xác thực và ủy quyền WWW

Tôi sắp đề cập đến ba kỹ thuật xác thực phổ biến. Đầu tiên tôi sẽ nói về điểm chung của cả ba: tiêu đề
xác thực của HTTP.

Câu chuyện của chúng ta bắt đầu, giống như ở Chương 1, với nữ anh hùng Alice đưa ra một yêu cầu đơn giản

để được đại diện:

Máy chủ GET/HTTP/


1.1: api.example.com

Nhưng lần này, máy chủ từ chối phục vụ đại diện được yêu cầu. Thay vào đó, nó phục vụ
một lỗi:

401 HTTP/1.1 trái phép WWW-Xác


thực: Vương quốc cơ bản="API của tôi"

Mã phản hồi 401 là yêu cầu ủy quyền. Tiêu đề WWW-Authenticate giải thích loại ủy quyền nào mà máy chủ sẽ

chấp nhận. Trong trường hợp này, máy chủ muốn máy khách sử dụng xác thực HTTP Basic.

Alice cần có được một số thông tin xác thực… bằng cách nào đó. Các chi tiết phụ thuộc vào cơ chế xác

thực được sử dụng. Sau khi có được thông tin xác thực, cô ấy có thể thực hiện lại yêu cầu HTTP, gửi

thông tin xác thực của mình trong tiêu đề Yêu cầu ủy quyền :

GET / HTTP/1.1
Máy chủ: api.example.com
Ủy quyền: YWxpY2U6cGFzc3dvcmQ= Cơ bản

Lần này, người phục vụ hy vọng sẽ cung cấp cho Alice sự đại diện mà cô ấy yêu cầu.

1. Nếu bạn bỏ qua lời khuyên này và triển khai các phiên trong API của mình, ID phiên sẽ trở thành một loại thông tin xác

thực tạm thời, được cung cấp cùng với mọi yêu cầu. Tất cả những gì bạn đã làm là thêm một lớp phức tạp khác lên trên hệ

thống thông tin xác thực hiện có.

250 | Chương 11: HTTP cho API


Machine Translated by Google

Xác thực cơ bản

Xác thực HTTP Basic được mô tả trong RFC 2617. Đó là sơ đồ tên người dùng/mật khẩu đơn giản. Người

dùng API phải thiết lập trước tên người dùng và mật khẩu—có thể bằng cách đăng ký tài khoản trên một

trang web liên kết hoặc bằng cách gửi email yêu cầu tài khoản API. Không có tiêu chuẩn nào về cách

yêu cầu tên người dùng và mật khẩu cho một trang web nhất định.

Tuy nhiên, điều đó sẽ xảy ra, khi Alice có tên người dùng và mật khẩu, cô ấy có thể thực hiện lại

yêu cầu HTTP ban đầu đó. Lần này cô ấy sử dụng tên người dùng và mật khẩu của mình để tạo một giá

trị cho Ủy quyền tiêu đề yêu cầu , như đã thấy trong phần trước.

Máy chủ xác thực cô ấy, chấp nhận yêu cầu và đưa ra một đại diện thay vì
lỗi 401:

HTTP/1.1 200 OK
Loại nội dung: application/xhtml+xml
...

Auth cơ bản rất đơn giản nhưng nó có hai vấn đề lớn. Đầu tiên là nó không an toàn. YWx

pY2U6cGFzc3dvcmQ= trông giống như mã hóa vô nghĩa, nhưng thực ra nó là chuỗi alice:password chạy qua

một biến đổi đơn giản, có thể đảo ngược được gọi là Base64.2. Điều này có nghĩa là bất kỳ ai theo

dõi kết nối Internet của Alice đều biết mật khẩu của cô ấy. Họ có thể mạo danh Alice bằng cách gửi

các yêu cầu HTTP bao gồm Ủy quyền: YWx pY2U6cGFzc3dvcmQ= cơ bản.

Sự cố này sẽ biến mất nếu API sử dụng HTTPS thay vì HTTP đơn giản. Ai đó theo dõi kết nối Internet

của Alice sẽ thấy cô ấy mở kết nối, nhưng yêu cầu và phản hồi sẽ được mã hóa bởi lớp SSL.

RFC 2617 xác định phương thức xác thực thứ hai có tên là Digest, phương pháp này tránh được sự cố

này ngay cả khi không sử dụng HTTPS. Tôi sẽ không đề cập đến Digest trong cuốn sách này vì Digest và

Basic có chung một vấn đề thứ hai , vấn đề này không phải là vấn đề lớn trên World Wide Web nhưng

lại rất nghiêm trọng trong thế giới API: những người sử dụng API thường không thể tin tưởng khách
hàng của họ.

Để làm rõ vấn đề, hãy tưởng tượng một API rất phổ biến như API Twitter. API này phổ biến đến mức

Alice đang sử dụng 10 ứng dụng khách khác nhau cho một API này. Có một số trên điện thoại di động

của cô ấy, một số trên máy tính để bàn của cô ấy và cô ấy đã cấp phép cho một số trang web khác nhau

để thay mặt cô ấy sử dụng API này. (Việc này xảy ra mọi lúc.)

Mười khách hàng khác nhau. Điều gì xảy ra khi một trong những khách hàng lừa đảo và bắt đầu đăng thư

rác vào tài khoản của Alice? (Điều này cũng xảy ra thường xuyên.)

2. Base64 được định nghĩa trong phần 6.8 của RFC 2045. Hầu hết các ngôn ngữ lập trình đều có triển khai Base64
trong thư viện tiêu chuẩn của họ.

Xác thực | 251


Machine Translated by Google

Sau cuộc tấn công, Alice phải thay đổi mật khẩu của mình. Cô ấy phải làm điều này để khách hàng lừa đảo

không còn có thông tin xác thực hợp lệ. Nhưng cô ấy đã đưa cho cả 10 khách hàng cùng một mật khẩu. Chín

trong số khách hàng vẫn đáng tin cậy, nhưng việc thay đổi mật khẩu sẽ phá vỡ cả 10.

Sau khi thay đổi mật khẩu, Alice phải thông qua chín khách hàng tốt của mình và cho họ biết mật khẩu mới.

Nếu một trong chín khách hàng lừa đảo, cô ấy phải thay đổi mật khẩu một lần nữa và thông qua tám khách

hàng tốt, thông báo lại cho từng khách hàng về mật khẩu mới của mình.

Điều này sẽ không thành vấn đề nếu ngay từ đầu Alice có thể cung cấp cho mỗi khách hàng một bộ thông tin

xác thực khác nhau. Đó là lúc OAuth xuất hiện.

OAuth 1.0

Theo OAuth, Alice cung cấp cho mỗi khách hàng một bộ thông tin xác thực riêng. Nếu cô ấy quyết định rằng
cô ấy không thích một trong những khách hàng, cô ấy sẽ thu hồi thông tin đăng nhập của khách hàng đó và

chín khách hàng còn lại không bị ảnh hưởng. Nếu một khách hàng lừa đảo và bắt đầu đăng thư rác dưới tên

của người dùng, nhà cung cấp dịch vụ có thể can thiệp và thu hồi thông tin xác thực đối với mọi phiên bản

của khách hàng đó—của Alice và của mọi người khác.

Có hai phiên bản OAuth. OAuth 1.0 (được xác định trong RFC 5849) hoạt động tốt khi cho phép các nhà phát

triển trang web hướng tới người tiêu dùng tích hợp với API của bạn. Nó bắt đầu thất bại khi bạn muốn cho

phép tích hợp các ứng dụng trên máy tính để bàn, thiết bị di động hoặc trong trình duyệt với API của mình.

OAuth 2.0 rất giống với 1.0 nhưng nó xác định cách xử lý các tình huống này.

Tôi sẽ mô tả ngắn gọn các khái niệm đằng sau OAuth bằng OAuth 1.0 và chỉ cho bạn cuốn Bắt đầu với OAuth

2.0 của Ryan Boyd (O'Reilly) để có phần giải thích chi tiết, dễ đọc về OAuth 2.0.

Đây là mã phản hồi 401 trông như thế nào khi máy chủ muốn khách hàng cung cấp một bộ thông tin xác thực
OAuth:

HTTP/1.1 401 Ủy quyền WWW trái


phép: OAuth Realm="API của tôi"

Để có được những thông tin xác thực đó là một quá trình phức tạp. Giả sử Alice đang sử dụng một trang web,

YouTypeItWePostIt.com. Cô nhìn thấy một tùy chọn kiểm soát siêu phương tiện cho cô biết rằng cô có thể

tích hợp tài khoản của mình trên example.net với tài khoản của mình trên YouTypeItWePostIt.com. Cô ấy có

thể làm điều này mà không cần nói cho YouTypeItWePostIt.com mật khẩu của mình trên example.net (xem Hình

11-2).

252 | Chương 11: HTTP cho API


Machine Translated by Google

Hình 11-2. YouTypeItWePostIt.com với lời nhắc đăng nhập qua example.net

Đây có vẻ là một ý tưởng hay đối với Alice, vì vậy cô ấy nhấp vào nút để kích hoạt điều khiển siêu phương

tiện. Chuyện gì xảy ra tiếp theo?

1. Máy chủ YouTypeItWePostIt.com bí mật yêu cầu một bộ thông tin xác thực tạm thời từ nhà cung cấp

API, api.example.net. Bước này hoàn toàn không yêu cầu sự tham gia của Alice.

2. Máy chủ YouTypeItWePostIt.com gửi chuyển hướng HTTP tới trình duyệt của Alice.

Alice rời khỏi trang web cô đang sử dụng và kết thúc trên một trang web do nhà cung cấp API,

example.net cung cấp.

Nếu Alice chưa đăng nhập vào example.net, cô ấy cần đăng nhập hoặc tạo tài khoản người dùng. Điều

này có nghĩa là nhập mật khẩu của cô ấy—nhưng lưu ý rằng cô ấy đang cung cấp mật khẩu Sample.net

của mình cho api.example.net chứ không phải cho YouTypeItWePostIt.com.

3. Sau khi đăng nhập, Alice thấy một trang web được liên kết với thông tin xác thực tạm thời có được ở

bước 1. Văn bản mà con người có thể đọc được của trang này giải thích cho Alice chuyện gì đang xảy

ra và hỏi cô ấy xem cô ấy có muốn ủy quyền cho một bộ api không Thông tin xác thực mã thông

báo .example.net cho YouTypeItWePostIt.com (xem Hình 11-3).

4. Alice đưa ra quyết định của mình và trình duyệt của cô ấy được chuyển hướng trở lại YouTypeItWePost-

tIt.com, trang web mà cô ấy đang sử dụng ban đầu.

5. a) Nếu Alice nói “không” ở bước 4, khách hàng đã không gặp may. Nó sẽ không nhận được gì

thông tin xác thực mã thông báo api.example.net từ Alice.

b) Nếu Alice nói “có” ở bước 4, khách hàng được phép trao đổi thông tin xác thực tạm thời có được

ở bước 1 để lấy một bộ thông tin xác thực mã thông báo thực. Những thông tin xác thực này có thể

được sử dụng để ký các yêu cầu HTTP bằng mật mã, tạo ra các tiêu đề Cấp phép giống như tiêu đề

trong yêu cầu này:

Xác thực | 253


Machine Translated by Google

GET / HTTP/1.1
Máy chủ: api.example.net
Ủy quyền: OAuth Realm="Example API",
oauth_consumer_key="rQLd1PciL0sc3wZ",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1363723000",
oauth_nonce="JFI8Bq",
oauth_signature= "4HBjJvupgIYbeEy4kEOLS%Ydn6qyV%UY"

Tại thời điểm đó, khách hàng có thể sử dụng API bình thường như thể đó là Alice.

Hình 11-3. Ví dụ.net yêu cầu thông tin xác thực của Alice thay mặt cho YouTypeItWePos‐
tIt.com

Tùy thuộc vào API, thông tin xác thực mã thông báo có thể là vĩnh viễn hoặc chúng có thể tự động hết hạn sau

một thời gian. (Sau khi chúng hết hạn, khách hàng sẽ cần gửi lại Alice thực hiện quy trình này nếu muốn tiếp

tục sử dụng API.) Thông tin xác thực mã thông báo có thể cấp cho khách hàng quyền truy cập vào mọi thứ Alice có

thể thực hiện với API hoặc họ có thể chỉ cho phép một tập hợp con về những gì Alice có thể làm. (Một hạn chế

phổ biến là quyền truy cập chỉ đọc vào API.)

Đây chỉ là một số trong số những thứ không được chỉ định trong tiêu chuẩn OAuth và phải được nhà cung cấp API

xác định.

Bạn có thể thấy rằng OAuth phức tạp hơn nhiều so với HTTP Basic Auth, nhưng—tôi không thể nhấn mạnh điều này đủ

—nó giúp Alice không phải cung cấp mật khẩu của mình cho 10 phần mềm khác nhau mà cô ấy không tin tưởng. Sự

phức tạp của OAuth mang lại một số tính năng hữu ích khác:

• Nếu Alice không thích những gì khách hàng đang làm thay mặt cô ấy, cô ấy có thể thu hồi mã thông báo của nó
thông tin xác thực.

254 | Chương 11: HTTP cho API


Machine Translated by Google

• Nếu nhà cung cấp API nhận thấy một phần mềm máy khách bị lừa đảo, nhà cung cấp có thể thu hồi thông tin xác thực

ứng dụng khách của mình. (Đó là oauth_consumer_key.) Điều này có nghĩa là API ngừng phân phát tất cả các bản sao

của ứng dụng khách đó.

• Không giống như HTTP Basic (nhưng giống như HTTP Digest), OAuth 1.0 có thể được sử dụng trên HTTP không an toàn

mà không tiết lộ thông tin xác thực của Alice. Thông tin xác thực mã thông báo là cần thiết để tạo phần

oauth_signature của tiêu đề Ủy quyền , nhưng thông tin xác thực không thực sự xuất hiện ở bất kỳ đâu trong tiêu

đề đó. Máy chủ (cũng biết thông tin xác thực của Alice) có thể xác minh rằng yêu cầu đã được ký bởi thông tin

xác thực của Alice, nhưng ai đó theo dõi yêu cầu sẽ không thể biết thông tin xác thực của cô ấy là gì. • Các giá

trị oauth_timestamp và oauth_nonce trong tiêu đề Ủy quyền ngăn chặn “các cuộc tấn công lặp lại”,

trong đó kẻ tấn công theo dõi các yêu cầu của Alice, sau đó thực hiện các yêu cầu tương tự để mạo danh cô ấy. (Xác

thực HTTP Digest cũng có tính năng này.)

Trường hợp OAuth 1.0 thất bại

OAuth 1.0 hoạt động tốt khi tất cả hành động diễn ra bên trong trình duyệt web của Alice. Điều gì sẽ xảy ra nếu Alice

đang sử dụng một ứng dụng dành cho máy tính để bàn?

Trong trường hợp đó, Alice cần tạm thời chuyển sang trình duyệt web của mình. Ở bước 2, thay vì chuyển hướng Alice đến

trang trên api.example.net, ứng dụng dành cho máy tính để bàn sẽ mở một cửa sổ trình duyệt mới được đặt cho trang đó.

Khi Alice đưa ra quyết định ở bước 4, sẽ không có nơi nào để api.example.net chuyển hướng cô ấy quay lại. Ở chế độ

nền, ứng dụng dành cho máy tính để bàn cần liên tục hỏi api.example.net xem Alice có ủy quyền (hoặc từ chối) thông tin

xác thực tạm thời hay không.

Đó là câu trả lời của OAuth 1.0 để tích hợp API vào ứng dụng máy tính để bàn mà không yêu cầu nhập tên người dùng/mật

khẩu. Sẽ hơi rắc rối một chút khi cửa sổ trình duyệt web đột nhiên bật lên khi bạn đang sử dụng một ứng dụng dành cho

máy tính để bàn, nhưng điều đó hoàn toàn có thể thực hiện được. Thật không may, có một số tình huống khác trong đó quy

trình năm bước mà tôi đã mô tả trước đây không hiệu quả hoặc hoàn toàn không hoạt động:

• Điều gì sẽ xảy ra nếu Alice đang sử dụng một ứng dụng trên điện thoại di động hoặc chơi trò chơi trên máy chơi

game? Sẽ rắc rối hơn nhiều khi đột nhiên bật lên một cửa sổ trình duyệt trên các thiết bị này. Nó thậm chí có

thể không thể. Một số thiết bị không có trình duyệt web. • Điều gì sẽ xảy ra nếu Alice là tác giả của

ứng dụng khách phần mềm api.example.net của riêng cô ấy? Liệu việc bắt cô ấy lấy thông tin đăng nhập tạm thời và

hỏi cô ấy xem cô ấy có muốn ủy quyền cho khách hàng của mình có thực sự hợp lý không?

• Điều gì sẽ xảy ra nếu Alice đang sử dụng một ứng dụng máy tính để bàn chạy bên trong trình duyệt web của cô ấy?

Thông tin xác thực tạm thời có thực sự cần thiết không? Ở bước 5, api.example.net không thể chỉ phân phát một

trang chứa mã thông báo truy cập thực và để ứng dụng trong trình duyệt đọc nó bằng mã JavaScript sao?

Xác thực | 255


Machine Translated by Google

OAuth 2.0 được thiết kế để đáp ứng các trường hợp sử dụng này.

OAuth 2.0

OAuth 2.0 được xác định trong RFC 6749. Nó chỉ định bốn quy trình khác nhau để nhận mã thông báo truy cập

OAuth (một lần nữa, tôi sẽ không đi sâu vào chi tiết; hãy xem Bắt đầu với OAuth 2.0 để tìm hiểu thêm):

• Bằng cách cung cấp “mã ủy quyền” (mục 1.3.1 của RFC 6749). Đây là hệ thống tôi đã mô tả cho OAuth

1.0. “Chủ sở hữu tài nguyên” (Alice) xác thực bằng “máy chủ ủy quyền” (đăng nhập vào example.net),

máy chủ này chuyển hướng cô ấy đến “máy khách” (api.example.net), máy chủ này sẽ cung cấp mã thông

báo truy cập.

• Thông qua “khoản trợ cấp ngầm” (mục 1.3.2 của RFC 6749). Đây là một lựa chọn tốt cho một ứng dụng

chạy bên trong trình duyệt web của Alice. Sau khi Alice đăng nhập vào Sample.net, cô ấy được chuyển

hướng đến api.example.net, điều này sẽ chuyển hướng cô ấy đến một URL chứa mã thông báo truy cập.

Không cần phải có thông tin xác thực tạm thời; ứng dụng trong trình duyệt chỉ có thể đọc mã thông

báo truy cập từ thanh địa chỉ của trình duyệt.

• Thông qua “thông tin xác thực mật khẩu của chủ sở hữu tài nguyên” (phần 1.3.3 của RFC 6749). Nghĩa

là, Alice cung cấp tên người dùng và mật khẩu example.net của mình cho khách hàng, khách hàng sẽ

trao đổi chúng để lấy mã thông báo truy cập OAuth.

Đây chính xác là điều OAuth đang cố tránh: Alice tiết lộ mật khẩu của mình cho một khách hàng không

đáng tin cậy. Nhưng trên thiết bị di động hoặc máy chơi game thì không có giải pháp thay thế nào phù
hợp.

Tại thời điểm này, một khách hàng độc hại có thể đánh cắp mật khẩu của Alice. Nhưng một khách hàng

hợp pháp sẽ quên mật khẩu của Alice ngay khi nhận được mã thông báo truy cập OAuth. Điều này có

nghĩa là một khách hàng hợp pháp sẽ không bị hỏng nếu Alice thay đổi mật khẩu của mình vì những lý

do khác. • Thông qua “thông tin xác thực của khách hàng” (mục 1.3.4 của RFC 6749). Điều này sẽ tránh

được rất nhiều rắc rối khi Alice là tác giả của chính khách hàng của mình. Khi Alice đăng ký khách

hàng của mình với api.example.net, cô ấy tự động được cấp một bộ thông tin xác thực sẽ cấp cho khách

hàng quyền truy cập miễn phí vào tài khoản example.net của chính cô ấy .

Là nhà cung cấp API, bạn không cần phải triển khai cả bốn luồng ứng dụng này. Nếu bạn đang viết một API

để phục vụ như một chương trình phụ trợ cho một ứng dụng di động, bạn chỉ cần triển khai luồng “thông tin

xác thực mật khẩu của chủ sở hữu tài nguyên”. Nhưng nếu bạn muốn các bên thứ ba tích hợp ứng dụng khách

với API của mình, bạn sẽ cần triển khai luồng ứng dụng mà khách hàng của bạn muốn sử dụng.

Khi nào nên từ bỏ OAuth


Do sự phức tạp của các tiêu chuẩn OAuth và các luồng ứng dụng khác nhau của chúng, bạn nên từ bỏ và bảo

vệ API của mình bằng cách sử dụng HTTP Basic hoặc HTTP Digest au‐

256 | Chương 11: HTTP cho API


Machine Translated by Google

sự thúc giục. Tôi khuyên bạn nên kiên trì và tìm hiểu cách OAuth hoạt động. Nếu cần, hãy nghiên cứu

và sao chép cách triển khai của một nhà cung cấp OAuth tên tuổi như Facebook.

Ưu điểm cơ bản của OAuth—việc tách tên người dùng và mật khẩu example.net của Alice khỏi thông tin xác

thực api.example.net của cô ấy —là một tính năng thực sự quan trọng. Theo tôi, chỉ có hai trường hợp

bạn có thể làm mà không cần nó:

• API của bạn là một trò giải trí phù phiếm. Nếu một khách hàng độc hại đánh cắp Alice

thông tin xác thực, nó không thể gây ra bất kỳ thiệt hại thực sự nào.

• Mỗi người dùng API của bạn sẽ viết ứng dụng khách của riêng mình. Khi đó, sẽ không có lợi ích bảo

mật nào khi tách Alice nhà phát triển khách hàng khỏi Alice người dùng cuối. Điều này có nghĩa

là khi Alice thay đổi mật khẩu của mình trên trang web, cô ấy cũng sẽ cần thay đổi mật khẩu của

mình trong tất cả các ứng dụng khách API của mình. Đây không phải là một vấn đề lớn.

Nếu bạn hiểu các vấn đề bảo mật, nhưng bạn không nghĩ API của mình sẽ trở nên đủ phổ biến để khiến các

ứng dụng khách độc hại trở thành vấn đề, thì bạn vẫn nên sử dụng OAuth.

Khi bạn bắt đầu sử dụng HTTP Basic, rất khó để chuyển tất cả ứng dụng khách của bạn sang OAuth.

Đừng tự nhốt mình khỏi thành công.3

Tiện ích mở rộng cho HTTP

Theo định nghĩa, khá nhiều API web dựa trên giao thức HTTP. Nhưng các khái niệm cơ bản của REST không

yêu cầu HTTP, cũng như ràng buộc siêu phương tiện yêu cầu bạn cung cấp các biểu diễn HTML.

Có hai phần mở rộng cho HTTP xác định các phương thức mới cụ thể để sử dụng trong API và ba giao thức

chính lấy HTTP làm điểm bắt đầu. Một trong những giao thức đó, CoAP, khác thường đến mức tôi dành cả

một chương (Chương 13) cho nó. WebDAV và HTTP 2.0 dựa chặt chẽ vào HTTP, vì vậy tôi sẽ trình bày chúng

ở đây cùng với một số phương thức HTTP mở rộng.

Phương pháp PATCH

• Được định nghĩa trong: RFC 5789 và các tiêu chuẩn khác

• Ngữ nghĩa giao thức: không an toàn cũng không bình thường

Tôi đã trình bày phương pháp này trong Chương 3 như một phần của bộ công cụ được đề xuất dành cho các nhà phát triển API.

Phương thức PATCH giải quyết vấn đề hiệu suất với HTTP PUT. PUT thay thế toàn bộ biểu diễn của tài

nguyên bằng một biểu diễn mới, có nghĩa là máy khách phải gửi lại

3. Khi API Twitter chuyển từ Xác thực cơ bản sang OAuth vào năm 2010, các nhà phát triển đã gọi sự kiện này là “OAuth‐

ngày tận thế.”

Tiện ích mở rộng cho HTTP | 257


Machine Translated by Google

toàn bộ sự thể hiện ngay cả khi nó chỉ thực hiện một thay đổi nhỏ. Phương thức PATCH cho phép

client chỉ gửi thay đổi mà nó muốn thực hiện.

Nhược điểm của phương pháp PATCH là máy khách và máy chủ phải thống nhất về loại phương tiện mới

cho các tài liệu vá lỗi. May mắn thay, bạn không cần phải tự mình nghĩ ra định dạng này. RFC 6902

xác định định dạng bản vá tiêu chuẩn cho JSON và đăng ký loại phương tiện application/json-patch

cho các tài liệu ở định dạng đó. RFC 5261 xác định định dạng bản vá cho tài liệu XML và “dự thảo-

wilde-xml-patch” Internet-Draft đăng ký loại phương tiện application /xml-patch+xml cho tài liệu ở

định dạng đó.

Phương thức LINK và UNLINK

• Được định nghĩa trong: Internet-Draft “phương thức liên kết snell”

• Ngữ nghĩa giao thức: bình thường nhưng không an toàn

Phương thức LINK tạo kết nối giữa hai tài nguyên. Có lẽ, khi tài nguyên A được liên kết với tài

nguyên B, một liên kết hypermedia tới B sẽ bắt đầu hiển thị trong các biểu diễn của A.

Nhưng liên kết được tạo ra như thế nào? Làm cách nào một yêu cầu HTTP có thể tham chiếu đến hai tài nguyên khác nhau?

Tất nhiên, bằng cách bao gồm cả hypermedia. Yêu cầu LINK hoặc UNLINK được gửi đến URL của tài
nguyên A và tài nguyên B được đề cập trong tiêu đề Liên kết . Mối quan hệ liên kết được liên kết

với tiêu đề Liên kết mô tả mối quan hệ mong muốn giữa A và B.

Đây là yêu cầu thêm một mục hiện có vào bộ sưu tập (đó là trường hợp sử dụng phổ biến cho mẫu bộ

sưu tập nhưng nó không được xác định trong AtomPub hoặc Collection+JSON):

LIÊN KẾT /collections/a6o HTTP/1.1 Máy


chủ: www.example.com Liên
kết: <http://www.example.com/items/4180>;rel="item"

Đây là yêu cầu xóa tài nguyên thứ hai khỏi chuỗi tài nguyên:

HỦY LIÊN KẾT /story/part1 HTTP/1.1 Máy


chủ: www.example.com Liên

kết: <http://www.example.com/story/part2>;rel="next"

Sau khi yêu cầu này được thực hiện, các tài nguyên tại /story/part1 và /story/part2 vẫn tồn tại.

Chỉ là không còn mối liên kết nào giữa chúng mà mối quan hệ liên kết là “tiếp theo”. Có lẽ /story/

part1 hiện có liên kết đến /story/part3 với rel="next".

Những phương pháp này không cần thiết về mặt kỹ thuật. Bạn có thể sao chép chức năng của chúng

bằng PUT. Nhưng họ đơn giản hóa mọi thứ. Họ chia ra một hoạt động chung—thao tác các liên kết siêu

phương tiện giữa các tài nguyên—và đặt cho nó ngữ nghĩa giao thức riêng.

Trong Chương 3, tôi đã đề cập rằng từ năm 1997 đến năm 1999, các phương thức này là một phần tiêu

chuẩn của HTTP. RFC 2616 đã xóa chúng vì không rõ lý do và cách thức thực hiện

258 | Chương 11: HTTP cho API


Machine Translated by Google

được dùng. Với sự phát triển của API web và sự ra đời của tiêu đề Liên kết , điều này rõ ràng hơn rất

nhiều.

Điều duy nhất ngăn cản tôi khuyến nghị sử dụng LINK và UNLINK là thực tế là Bản nháp Internet mô tả chúng

chưa được phê duyệt dưới dạng RFC.

WebDAV
• Được định nghĩa trong: RFC 4918 và các tiêu chuẩn khác

• Ngữ nghĩa giao thức: Hoạt động của hệ thống tập tin

Mục tiêu của WebDAV là giúp dễ dàng xuất bản tài nguyên HTTP cho các tệp và thư mục trên hệ thống tệp từ

xa. WebDAV định nghĩa rất nhiều phương thức HTTP mới và các phần mở rộng khác đến mức nó gần như có thể

được coi là một giao thức khác.

Các ứng dụng phổ biến nhất của WebDAV là Sharepoint của Microsoft và hệ thống kiểm soát phiên bản

Subversion. Chúng tôi thực sự không coi chúng là API và hầu hết các API hoạt động giống như hệ thống tệp

từ xa (S3 của Amazon, API Dropbox, v.v.) không sử dụng WebDAV.

Chúng là các tiêu chuẩn fiat sử dụng các phương thức HTTP tiêu chuẩn như PUT và phân phát siêu dữ liệu

bằng cách sử dụng các biểu diễn XML hoặc JSON đặc biệt. Nói cách khác, chúng trông giống như các API khác
ngày nay.

Giống như AtomPub, WebDAV là một tiêu chuẩn mở bị nhiều người bỏ qua vì nó không phù hợp với những ý

tưởng hiện đại về giao diện của một API. Tuy nhiên, việc hiểu WebDAV vẫn hữu ích vì đây là công ty tiên

phong đầu tiên trong lĩnh vực API. Dưới đây là một số tính năng thú vị hơn của WebDAV.

• WebDAV triển khai mẫu bộ sưu tập (Chương 6) bằng cách xác định các tài nguyên “bộ sưu tập” hoạt động

giống như các thư mục trên hệ thống tệp cục bộ. Các tài nguyên này phản hồi GET và DELETE. WebDAV
cũng xác định một phương thức HTTP hoàn toàn mới, MKCOL, tạo ra một bộ sưu tập mới.

Máy khách tải tệp lên bằng cách gửi yêu cầu PUT tới bất kỳ URL nào nó chọn cho tài nguyên mới. RFC

5995 là một tiện ích mở rộng cho phép khách hàng tải lên các tệp mới bằng cách sử dụng POST để nối

thêm. Trong trường hợp đó, máy chủ chọn URL của tài nguyên mới chứ không phải máy khách.

• Một tệp trên hệ thống tệp cục bộ của bạn chứa dữ liệu nhưng nó cũng có siêu dữ liệu liên quan: tên

tệp, ngày tạo tệp, v.v. Tài nguyên WebDAV thể hiện siêu dữ liệu này dưới dạng “thuộc tính” như tên

hiển thị và ngày tạo.

WebDAV định nghĩa phương thức HTTP PROPPATCH để sửa đổi các thuộc tính của tài nguyên và phương thức

PROPFIND để tìm kiếm bộ sưu tập nhằm tìm ra các tài nguyên có thuộc tính nhất định.

Tiện ích mở rộng cho HTTP | 259


Machine Translated by Google

• WebDAV cho phép máy khách khóa tài nguyên một cách rõ ràng (sử dụng các phương thức HTTP mới LOCK

và UNLOCK) để các máy khách khác không thể truy cập được. Điều này có thể được sử dụng với các kỹ

thuật mà tôi đã mô tả trước đó trong chương này để tránh vấn đề mất bản cập nhật. • WebDAV

định nghĩa các phương thức HTTP mới MOVE và COPY. Chúng hoạt động giống như các hoạt động hệ thống

tập tin tương đương. MOVE thay đổi URL của tài nguyên và COPY đưa ra một bản sao đại diện hiện tại

của tài nguyên tại một số URL khác.

WebDAV cũng xác định một điều khiển siêu phương tiện mới cho các phương thức này: tiêu đề yêu cầu

Đích . Tiêu đề này chứa URL mới của tài nguyên hoặc URL để sử dụng cho bản sao. So sánh tiêu đề

Yêu cầu liên kết , như được sử dụng với các phương thức LINK và UNLINK.

• WebDAV xác định năm mã trạng thái HTTP mới, bao gồm một số mã có thể trông hấp dẫn ngay cả khi bạn

không sử dụng WebDAV, như 423 (Đã khóa) và 507 (Không đủ bộ nhớ). Nhưng tôi không khuyên bạn nên

sử dụng các tính năng WebDAV bên ngoài Web-DAV. Thay vào đó hãy quay lại mã trạng thái tiêu chuẩn.

Bạn có thể sử dụng 409 (Xung đột) thay vì 423 (Đã khóa) và cung cấp ngữ cảnh bổ sung trong tài

liệu chi tiết về vấn đề.

HTTP 2.0

• Được định nghĩa trong: Internet-Draft “draft-ietf-httpbis-http2”

• Ngữ nghĩa giao thức: Giống với HTTP 1.1

HTTP 2.0 là phiên bản kế thừa của HTTP hiện tại được xác định trong RFC 2616 và các RFC thay thế của

nó. HTTP 2.0 dựa trên SPDY, một tiêu chuẩn công ty do Google xác định nhằm bổ sung lớp hiệu suất bên

trên HTTP. Hầu hết các trình duyệt web hiện nay đều hỗ trợ SPDY và nhiều trang web lớn cung cấp dữ liệu

bằng SPDY nếu máy khách hỗ trợ.

Mục tiêu của HTTP 2.0 là cải thiện hiệu suất của HTTP trong khi vẫn duy trì ngữ nghĩa giao thức của nó.

Bất chấp cái tên hoành tráng của nó, HTTP 2.0 sẽ không mang đến các tính năng mới làm lung lay nền tảng

thiết kế API. Cho dù bạn đang phát triển API, ứng dụng khách API hay trang web, bạn đều có thể giả vờ

như mình đang sử dụng HTTP 1.1 và để lớp tương thích tự động chuyển đổi giữa HTTP 1.1 và 2.0.

Khi tôi viết bài này, vẫn còn quá sớm trong quá trình phát triển để nói chính xác HTTP 2.0 sẽ hoạt động

như thế nào. Nó có thể trông không giống SPDY. Nhưng nó cần giải quyết các vấn đề mà SPDY giải quyết,

có nghĩa là nó có thể sẽ có hai tính năng sau:

• HTTP 2.0 sẽ tiết kiệm băng thông bằng cách nén các tiêu đề HTTP, điều này không làm được

hợp pháp theo HTTP 1.0.

• Máy khách HTTP 2.0 sẽ có thể gửi nhiều yêu cầu đồng thời (“luồng”) đến máy chủ qua một kết nối

TCP. Điều này tương tự như tính năng đường ống

260 | Chương 11: HTTP cho API


Machine Translated by Google

của HTTP 1.1, nhưng như tôi đã đề cập trước đó, việc tạo đường dẫn không giúp ích nhiều
cho hiệu suất. HTTP 2.0 cần bao gồm một tính năng giống như đường ống thực sự hoạt động.

Những cải tiến kỹ thuật này sẽ có tác động tích cực lớn đến thiết kế API. Chúng sẽ loại bỏ nhu
cầu về một tập hợp chung các mẫu thiết kế API giúp cải thiện hiệu suất bằng cách kết hợp các
yêu cầu lại với nhau.4 Các mẫu này cho phép khách hàng tìm nạp (hoặc cập nhật) các biểu diễn
của nhiều tài nguyên bằng một yêu cầu HTTP duy nhất. Không có cách tiêu chuẩn nào để đóng gói
các “yêu cầu ảo” này lại với nhau, nhưng làm như vậy sẽ tiết kiệm rất nhiều thời gian vì mọi
yêu cầu HTTP 1.1 đều có chi phí thiết lập lớn.

HTTP 2.0 sẽ loại bỏ chi phí thiết lập đó. Thực hiện 20 yêu cầu HTTP và nhận được 20 phản hồi
sẽ nhanh gần như thực hiện một yêu cầu lớn và nhận được một phản hồi lớn.
Sẽ không còn nhu cầu API có các tính năng hàng loạt đặc biệt nữa.

4. Để có giải thích rõ ràng về các mẫu này, hãy xem Chương 11 của Sách dạy nấu ăn về dịch vụ web RESTful (O'Reilly).

HTTP 2.0 | 261


Machine Translated by Google
Machine Translated by Google

CHƯƠNG 12

Mô tả tài nguyên và dữ liệu được liên kết

Các định dạng dữ liệu tôi đề cập trong cuốn sách này chủ yếu được sử dụng để cho phép các
nguồn tài liệu nói về chính chúng. Nghĩa là, khách hàng gửi yêu cầu GET tới URL của tài
nguyên và nhận được bản trình bày của chính tài nguyên đó. Tôi gọi đây là chiến lược đại diện
egy.

Nhưng sự thể hiện của tài nguyên A cũng có thể nói lên điều gì đó về tài nguyên B.
Tài liệu Collection+JSON đơn giản này là sự thể hiện của một tài nguyên (một bộ sưu tập)
nhưng nó có điều gì đó để nói về hai tài nguyên khác (các mục trong bộ sưu tập):

{ "bộ sưu tập": {

"phiên bản" : "1.0",


"href" : "http://www.youtypeitwepostit.com/api/",

"mặt hàng" : [

{ "href" : "/api/messages/21818525390699506", "data":


[ { "name":
"text", "value": "Test." }

] },

{ "href" : "/api/messages/3689331521745771", "data":


[ { "name":
"text", "value": "Xin chào." }

] }

]
}
}

Tôi gọi đây là chiến lược mô tả. Với chiến lược mô tả, phần trình bày dành phần lớn thời
gian để nói về các tài nguyên khác ngoài tài nguyên mà nó đại diện.

263
Machine Translated by Google

Tất cả các định dạng hypermedia đều kết hợp các chiến lược trình bày và mô tả ở một mức độ nào

đó, nhưng có một nhóm định dạng tập trung chủ yếu vào chiến lược mô tả: các định dạng lấy cảm

hứng từ mô hình dữ liệu Khung mô tả tài nguyên (RDF) và liên kết với phong trào Web ngữ nghĩa. .

Tôi đã không đề cập đến các định dạng này trong Chương 10 bởi vì, theo quan điểm REST, chúng kỳ

lạ. Chiến lược mô tả thuần túy vi phạm các ràng buộc Fielding. Các tài liệu RDF thường mô tả các

tài nguyên mà từ góc độ REST là “không tồn tại”. Để hiểu những tài liệu này đang nói về điều gì,

bạn phải áp dụng một cách suy nghĩ khác.

May mắn thay, phong trào Web ngữ nghĩa làn sóng thứ hai có tên là Dữ liệu liên kết nhằm mục đích

tái tập trung RDF vào chiến lược biểu diễn. Đây là một tin tuyệt vời vì có một số định dạng dữ

liệu hữu ích bắt nguồn từ RDF và một ngôn ngữ rất mạnh để tạo các cấu hình máy có thể đọc được:

Lược đồ RDF.

Nhưng trước khi tôi chuyển sang Dữ liệu được Liên kết, bạn cần hiểu RDF. Mọi thứ trong chương

này đều dựa trên, lấy cảm hứng từ hoặc được thiết kế để phản ứng với mô hình dữ liệu RDF. Bạn

cần hiểu tài liệu RDF trông như thế nào, ý nghĩa của chúng và tại sao ngay từ đầu phong trào Dữ

liệu được liên kết lại cần thiết.

RDF
• Các loại phương tiện: ứng dụng/rdf+xml, văn bản/rùa, v.v. •

Được xác định trong: Các tiêu chuẩn mở W3C, được xác định tại đây và đáng

chú ý ở đây • Phương tiện: văn bản thuần túy,

XML, HTML, v.v. • Ngữ nghĩa giao thức: điều hướng

bằng GET • Ngữ nghĩa ứng dụng: không có

Đây là mô tả RDF của một ô trong mê cung Mê cung+XML:

<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:maze="http://alps.io/example/maze#">
<rdf:Description about="http://example.com/cells/M">
<maze:title>Hành lang vào</maze :title>
<maze:east Resource="http://example.com/cells/N">
<maze:west Resource="http://example.com/cells/L">
</rdf:Description>
< /rdf:RDF>

Có nhiều cách viết RDF, bao gồm phiên bản HTML có tên RDFa và phiên bản văn bản thuần túy có tên

Turtle. Bạn vừa thấy phiên bản XML, được gọi là RDF+XML.

Đây là mô tả của Rùa về ô mê cung có ý nghĩa giống hệt nhau:

<http://example.com/cells/M> <http://alps.io/example/maze#title>
"Hành lang vào" .
<http://example.com/cells/M> <http://alps.io/example/maze#east>

264 | Chương 12: Mô tả tài nguyên và dữ liệu được liên kết


Machine Translated by Google

<http://example.com/cells/N> .
<http://example.com/cells/M> <http://alps.io/example/maze#west> <http://
example.com/cells/L> .

Thiết lập một số phím tắt Rùa và bạn có thể biểu thị cùng một thông tin theo cách gọn gàng hơn:

@prefix mê cung: <http://alps.io/example/maze#> .


<http://example.com/cells/M> mê cung:title "Hành lang vào" ;
mê cung:phía đông <http://example.com/cells/
N> ; mê cung:tây <http://example.com/cells/L> .

Cả ba tài liệu này đều mô tả cùng một tài nguyên: tài liệu có URI http://example.com/cells/M.

Trong RDF+XML, URI được mô tả sẽ đi vào thuộc tính about của thẻ <Description> . Trong Turtle,

URI đó nằm ở đầu dòng, trong dấu ngoặc nhọn. (Giống như cách tiêu đề Liên kết HTTP đặt URL

đích của nó trong dấu ngoặc nhọn.)

Mỗi tài liệu này đều đưa ra những xác nhận giống nhau về tài nguyên mà nó mô tả.
Mỗi người đều nói rằng tài nguyên có một thuộc tính được gọi là http://alps.io/example/

maze#title, với giá trị của thuộc tính này là chuỗi ký tự Hành lang lối vào.

Mỗi tài liệu cũng nói rằng tài nguyên có hai thuộc tính được gọi là http://alps.io/ example/

maze#east và http://alps.io/example/maze#west. Các thuộc tính này hoạt động giống như các mối

quan hệ liên kết mở rộng. Giá trị của chúng là URI (chẳng hạn như http://example.com/cell/L).
Họ giải thích mối quan hệ giữa tài nguyên ở phía bên phải của thuộc tính và tài nguyên ở phía
bên trái:

<http://example.com/cells/M> <http://alps.io/example/maze#west> <http://


example.com/cells/L> .

Dịch theo thuật ngữ của con người thì câu nói đó của Rùa là “ô L nằm ở phía tây ô M”.

RDF cung cấp cho bạn một khuôn khổ để nói về ngữ nghĩa ứng dụng của tài nguyên. Bạn có thể nói
về các mối quan hệ liên kết kết nối một tài nguyên với tài nguyên khác và các bộ mô tả ngữ

nghĩa liên kết nó với trạng thái tài nguyên của chính nó. Nhưng không giống như các định dạng

khác, thuộc tính RDF không thể là các chuỗi ngắn như “title” và “east”. Chúng chỉ có thể là
URI, như http://Alps.io/example/maze#title và http://alps.io/example/maze#east. Bạn có thể sử

dụng tiền tố Turtle và không gian tên XML để rút ngắn các URI thành maze:title và maze:east,

nhưng đằng sau hậu trường, chúng vẫn là các URI.

RDF coi URL là URI


Vì vậy, tài liệu RDF mô tả một ô mê cung bằng cách sử dụng một số thuộc tính như http://alps.io/

example/maze#title. Những đặc tính này có ý nghĩa gì ?

Trong thế giới REST, câu hỏi này đã có câu trả lời rõ ràng. Một http: URL xác định một tài
nguyên trên Web và nếu bạn gửi yêu cầu GET tới URL đó, bạn sẽ nhận được một thông báo thể hiện
trạng thái của tài nguyên.

RDF | 265
Machine Translated by Google

Nếu bạn gửi yêu cầu GET tới http://alps.io/example/maze, bạn sẽ nhận được tài liệu ALPS.

Tra cứu “phía đông” và “tiêu đề” trong tài liệu đó và bạn sẽ nhận được những lời giải thích mà con người có thể đọc được.

Điều này không đủ để tự mình thu hẹp khoảng cách ngữ nghĩa, nhưng nếu ứng dụng khách tự động của bạn gặp

khó khăn do không hiểu điều gì đó thì bạn, với tư cách là nhà phát triển, sẽ biết phải đi đâu để khắc

phục sự cố.

Nhưng RDF không coi URL là URL. Nó coi chúng như các URI, một thuật ngữ mà tôi chưa đề cập nhiều kể từ

Chương 4. URI xác định một tài nguyên, giống như một URL, nhưng không có gì đảm bảo rằng bạn có thể sử

dụng máy tính để có được sự thể hiện của tài nguyên đó. Đây là lý do tại sao tôi đã hạ thấp tầm quan

trọng của URI trong suốt cuốn sách này. Như tôi đã nói trong Chương 4, việc xác định tài nguyên của bạn

bằng URI khiến bạn không thể đáp ứng nhiều ràng buộc Fielding.

Nhưng tôi đã sử dụng http: URI trong tài liệu RDF của mình. Đó là những URL. Vậy là tôi an toàn rồi phải

không? Thực ra là không, tôi không an toàn. Đối với RDF, ngay cả http: URL cũng không là gì ngoài URI.

URI http://example.com/cells/N có thể trông hấp dẫn, nhưng từ góc độ RDF, không có gì đảm bảo rằng việc

thực hiện yêu cầu GET tới URI đó sẽ mang lại cho bạn sự đại diện. Máy khách RDF có thể dùng thử và xem

điều gì xảy ra, nhưng không được phép cho rằng điều gì đó sẽ xảy ra.

Nếu bạn đã gửi yêu cầu HTTP GET tới http://example.com/cells/M và nhận lại một trong các tài liệu RDF

này, chúng tôi sẽ nói rằng bạn đã có "bản trình bày" của tài nguyên tại http:// example.com /ô/M. Nhưng

trong thực tế, nếu bạn gửi yêu cầu GET đó, bạn sẽ gặp lỗi 404. http://example.com/cells/M là một tưởng

tượng, một URI mẫu mà tôi đã tạo ra cho mục đích của cuốn sách này. Vì vậy, chúng tôi không thể nói rằng

các tài liệu RDF này là “sự thể hiện” của tài nguyên đó.

Chúng là những mô tả về một tài nguyên, từ góc độ REST, không tồn tại.

Theo RDF, điều này hoàn toàn hợp pháp. Bạn có thể viết mô tả về một tài nguyên không có đại diện. Các

tài liệu RDF thường đề cập đến http: URI không trỏ đến bất kỳ điều gì cụ thể.

Với các định dạng dữ liệu khác, nếu bạn nhìn thấy một liên kết, bạn biết rằng tài liệu đang cố gắng cho

bạn biết về yêu cầu HTTP mà bạn có thể thực hiện. Để trích dẫn định nghĩa của Fielding về siêu phương

tiện, liên kết là “thông tin kiểm soát ứng dụng” giải thích những gì ứng dụng khách HTTP của bạn có thể
thực hiện tiếp theo.

Nhưng đối với tiêu chuẩn RDF, không có “ứng dụng” nào được “kiểm soát”.

Các liên kết không làm gì khác ngoài việc đặt tên cho các kết nối trừu tượng giữa các tài nguyên trừu tượng như nhau.

Bạn phải suy luận về những mối liên hệ đó chứ không phải theo dõi chúng để xem những gì ở phía bên kia.

Khi nào nên sử dụng chiến lược mô tả


Từ góc độ REST, điều này có vẻ khá điên rồ, nhưng có một số lý do chính đáng để sử dụng chiến lược mô tả

tài nguyên.

266 | Chương 12: Mô tả tài nguyên và dữ liệu được liên kết


Machine Translated by Google

Đầu tiên, mô tả tài nguyên cho phép bạn nói về tài nguyên khi bạn không kiểm soát việc trình
bày. Điều này có thể là do tài nguyên được kiểm soát bởi một máy chủ khác (như tài nguyên
OpenID xác định một trong những người dùng của bạn) hoặc do định dạng trình bày cố định. Bạn
có thể sử dụng chiến lược mô tả để nói lên tài nguyên của người khác.

Thứ hai, nhiều API hiện có phục vụ các biểu diễn không chứa điều khiển siêu phương tiện.
Việc thêm siêu phương tiện vào các tài liệu đó có thể phá vỡ các ứng dụng khách hiện có hoặc
vi phạm tiêu chuẩn. Nhưng với định dạng mô tả tài nguyên, bạn có thể thêm chú thích “bộ xương
ngoài” của cụm từ: [<phrase role="keep- together">hypermedia</phrase>] lên trên một tài liệu
không biết về hypermedia. JSON-LD, mà tôi đã đề cập trong Chương 8 và sẽ quay lại trong phần
sắp tới, được thiết kế chỉ cho mục đích này.

Cuối cùng, bạn có thể sử dụng chiến lược mô tả để nói về một nguồn tài nguyên không có đại
diện vì nó không có trên Web. Tôi đã đề cập ở Chương 4 rằng ấn bản in của cuốn sách này là
một tài nguyên có URI nổi tiếng, urn:isbn:9781449358063. Bạn không thể NHẬN bản trình bày của

tài nguyên đó, nhưng bạn có thể NHẬN tài liệu RDF mô tả nó.

Giả sử bạn gửi yêu cầu GET tới http://www.example.com/book-lookup/ 9781449358063 và nhận được
phản hồi sau:

HTTP/1.1 200 OK Loại

nội dung: văn bản/rùa

Lược đồ @prefix: <http://schema.org/> .


<urn:isbn:9781449358063> a Schema:Book ;

lược đồ:name "API Web RESTful" ; lược

đồ:inLanguage "en" ; lược đồ:isbn


"9781449358063" ; lược đồ:tác giả

_:mike ; lược đồ:tác giả

_:leonard .

_:mike a Schema:Person ;
lược đồ:tên "Mike Amundsen" .

_:leonard a lược đồ:Person ; lược


đồ:tên "Leonard Richardson" .

Phần thân thực thể mô tả một tài nguyên: “phiên bản in của API Web RESTful,” được xác định
bởi URI urn:isbn:9781449358063. URI này có một vấn đề lớn: bạn không thể sử dụng nó để thể
hiện tài nguyên. Đó là lý do tại sao khi thiết kế API web, chúng tôi không sử dụng URI. Chúng
tôi tạo các URL http: hoặc https: dựa trên tên miền mà chúng tôi kiểm soát. Chúng tôi tuyên
bố rằng các URL đó tương ứng với mọi thứ trong thế giới thực và chúng tôi cung cấp các đại
diện nắm bắt trạng thái của những thứ trong thế giới thực đó.

Đó không phải là điều tôi đã làm ở đây. Tôi đã tạo tài nguyên thứ hai, “đầu ra của chức năng
tra cứu sách”, được xác định bằng URL http://www.example.com/book-lookup/

Khi nào nên sử dụng Chiến lược mô tả | 267


Machine Translated by Google

9781449358063. Tài nguyên này mô tả trạng thái tài nguyên của vật thể trong thế giới thực được
xác định bởi urn:isbn:9781449358063, thay vì cố gắng thể hiện trực tiếp tài nguyên đó.
Sự thể hiện của nó đưa ra một số khẳng định về một sự vật trong thế giới thực. Nó nói rằng vật

trong thế giới thực là một cuốn sách (một lược đồ: Sách). Tiêu đề của cuốn sách là “API Web

RESTful”, được viết bằng tiếng Anh và có hai tác giả, đều là con người (_mike a Schema:Person),
mỗi tác giả có một tên. (lược đồ: tên)..

Có một ý tưởng thực sự tốt ở đây. Nếu 10 tổ chức khác nhau xác định 10 API web liên quan đến
sách thì chúng tôi sẽ có 10 URL khác nhau cho bất kỳ ISBN nhất định nào. Sẽ phải mất thêm công
sức để xác định rằng cách trình bày của http://example.com/books/ 9781449358063 và cách trình

bày của http://api.example.org/work? isbn=9781449358063 đang nói về cùng một cuốn sách. Nhưng
nếu tất cả các URL đó phục vụ các tài liệu RDF mô tả urn:isbn:9781449358063, thì rõ ràng là
tất cả các trình bày đều nói về cùng một điều cơ bản.

Như tôi đã nói, đây là một ý tưởng tuyệt vời… dành cho sách in. Nó không hoạt động tốt đối với
các tài nguyên thiếu mã định danh duy nhất. Lấy con người. Bạn có thể sử dụng RDF và từ vựng
của lược đồ.org để đưa ra mọi loại khẳng định về một con người:

HTTP/1.1 200 OK
Loại nội dung: văn bản/rùa

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . Lược đồ


@prefix: <http://schema.org/> . _:Jennifer a
Schema:Person ;
lược đồ:name "Jennifer Gallegos" ; lược
đồ:ngày sinh "1987-08-25" .

Tài liệu RDF/Rùa này mô tả một tài nguyên. Nó nói rằng tài nguyên là một người có tên và ngày
sinh nhất định. Nhưng không có sơ đồ URI được thống nhất cho mọi người1 nên tài nguyên được đề
cập không có URI. Nó chỉ có một mã định danh nội bộ, “Jennifer”.

Tài liệu này là một tập hợp các xác nhận về một tài nguyên ẩn danh. Không có cách thống nhất
nào để xác định con người mà chúng ta đang nói đến. Nếu 10 API phục vụ các mô tả RDF của cùng
một người thì không có cách nào rõ ràng để phát hiện ra tất cả chúng đều đang nói về cùng một
người.

Tại thời điểm này, bạn cũng có thể tạo một URL http: cho tài nguyên cá nhân của mình . Sau đó,
bạn có thể cung cấp bản trình bày về tài nguyên khi ai đó thực hiện yêu cầu GET tới URL của
tài nguyên đó. Và một khi bạn quyết định sử dụng chiến lược biểu diễn thay vì chiến lược mô
tả, bạn có thể muốn sử dụng định dạng dữ liệu có khả năng kiểm soát siêu phương tiện tốt hơn
RDF/XML hoặc RDF/Turtle.

1. Acct: Lược đồ URI, được xác định trong “draft-ietf-appsawg-acct-uri” của Internet-Draft, không thể xác định được con người

nhưng nó có thể xác định tài khoản người dùng. Đối với nhiều API, điều đó đủ gần.

268 | Chương 12: Mô tả tài nguyên và dữ liệu được liên kết

You might also like