Trong các bài trước, chúng ta đã tìm hiểu cách xây dựng Content Tree, tạo Document Type và tổ chức nội dung trong Umbraco 13. Project thực hành hiện có node Bookstore Home cùng hai category Lịch sử và Triết học.
Ở Day 4, chúng ta sẽ chuyển từ việc quản lý nội dung trong Backoffice sang việc truy vấn nội dung thông qua Content Delivery API. Đây là API tích hợp sẵn của Umbraco, cho phép hệ thống khác lấy nội dung đã publish dưới dạng JSON.
Mặc dù Frontend có thể là Next.js, React hoặc một ứng dụng mobile, bài viết này chỉ tập trung vào phía Umbraco: gọi API, đọc JSON, truy vấn danh sách nội dung và hiểu các tham số quan trọng. Phần tích hợp Frontend sẽ được trình bày trong series riêng.
1. Content Delivery API là gì?
Content Delivery API là thành phần giúp Umbraco hoạt động như một Headless CMS. Thay vì bắt buộc phải render HTML trực tiếp, Umbraco có thể cung cấp dữ liệu nội dung cho các ứng dụng khác thông qua HTTP API.
Ví dụ, với website nhà sách, Umbraco quản lý các nội dung sau:
- Bookstore Home: trang chủ.
- Lịch sử: category sách lịch sử.
- Triết học: category sách triết học.
Frontend có thể gọi API để nhận dữ liệu JSON, sau đó tự quyết định cách hiển thị menu, tiêu đề, danh sách sách hoặc trang chi tiết.
Trong bài này, chúng ta sẽ kiểm tra API trực tiếp bằng trình duyệt, Swagger hoặc một công cụ gửi HTTP request. Không cần xây dựng Frontend để hoàn thành các bài thực hành.
2. Chuẩn bị trước khi gọi API
2.1. Bật Content Delivery API
Content Delivery API là tính năng cần được bật trong cấu hình Umbraco. Mở file appsettings.json và kiểm tra cấu hình sau:
{
"Umbraco": {
"CMS": {
"DeliveryApi": {
"Enabled": true
}
}
}
}
Nếu project đã có cấu hình này thì không cần thêm lần nữa. Hãy kiểm tra cấu hình hiện có trước khi chỉnh sửa để tránh ghi đè các thiết lập khác.
2.2. Publish nội dung
Trong Umbraco Backoffice, hãy kiểm tra:
- Node Bookstore Home đã được tạo và publish.
- Hai category Lịch sử và Triết học đã được tạo dưới Bookstore Home.
- Các Document Type và property cần kiểm tra đã được cấu hình đúng.
- Nếu có thay đổi nội dung, hãy publish lại để dữ liệu mới có thể được truy vấn.
Lưu ý: Content Delivery API trả về nội dung đã publish theo mặc định. Nội dung còn ở trạng thái draft không tự động xuất hiện trong response thông thường.
2.3. Kiểm tra Swagger
Trong môi trường Development, bạn có thể mở đường dẫn Swagger của project:
https://localhost:44366/umbraco/swagger
Thay port 44366 bằng port HTTPS thực tế của project. Nếu Swagger có danh sách API, hãy chọn định nghĩa liên quan đến Umbraco Delivery API.
Nếu Swagger không hiển thị các endpoint mong muốn, điều đó chưa đủ để kết luận Content Delivery API bị lỗi. Hãy thử gọi endpoint trực tiếp ở các phần dưới đây và kiểm tra cấu hình của project.
3. Day 4.1: Lấy một Content Item và phân tích JSON
Umbraco cung cấp endpoint để lấy một content item theo GUID hoặc route path.
3.1. Endpoint lấy một item theo GUID
GET /umbraco/delivery/api/v2/content/item/{id}
Trong đó id là GUID của content item, không phải integer node ID của Umbraco.
Ví dụ, để lấy Bookstore Home, trước tiên hãy tìm GUID thật của node này trong Backoffice. Sau đó thay GUID vào URL:
GET https://localhost:44366/umbraco/delivery/api/v2/content/item/YOUR-BOOKSTORE-HOME-GUID
YOUR-BOOKSTORE-HOME-GUID chỉ là placeholder. Hãy thay bằng GUID thật của node trong project.
Nếu muốn lấy item theo route path, có thể sử dụng endpoint:
GET /umbraco/delivery/api/v2/content/item/{path}
Giá trị path phải phù hợp với route của content item trong project. Với website có cấu hình nhiều root hoặc nhiều hostname, cần chú ý cách Umbraco xác định root content item và route.
3.2. Phân tích JSON Response
Khi request thành công, API trả về thông tin content item dưới dạng JSON. Ví dụ rút gọn dưới đây chỉ minh họa cấu trúc response; GUID, property alias và giá trị cụ thể có thể khác trong project của bạn.
{
"name": "Bookstore Home",
"contentType": "bookstoreHome",
"id": "YOUR-BOOKSTORE-HOME-GUID",
"createDate": "2026-10-01T08:00:00Z",
"updateDate": "2026-10-15T10:30:00Z",
"route": {
"path": "/",
"startItem": {
"id": "YOUR-BOOKSTORE-HOME-GUID",
"path": "bookstore-home"
}
},
"properties": {
"siteTitle": "Nhà sách Trực tuyến",
"welcomeText": "Chào mừng bạn đến với cửa hàng sách!"
},
"cultures": {}
}
Các trường đáng chú ý:
- name: Tên content item trong Umbraco.
- contentType: Alias của Document Type, chẳng hạn
bookstoreHome. - id: GUID định danh của content item.
- route.path: Route của nội dung theo cấu hình hiện tại.
- properties: Các property được API trả về, dựa trên Document Type và dữ liệu đã publish.
- cultures: Thông tin liên quan đến các culture của nội dung, tùy cấu hình và trạng thái variant.
Quan trọng: Các property như siteTitle và welcomeText trong ví dụ chỉ xuất hiện nếu Document Type thực tế có những alias đó và dữ liệu được publish. Không nên giả định mọi node đều có cùng danh sách property.
3.3. Thực hành kiểm tra response
Sau khi gọi API, hãy kiểm tra các câu hỏi sau:
- Giá trị
namecó phải Bookstore Home không? contentTypecó khớp alias Document Type không?- GUID trả về có đúng với node đang truy vấn không?
route.pathcó đúng với route dự kiến không?- Những property nào thực sự xuất hiện trong response?
Đây là cách tốt để xác minh API dựa trên dữ liệu thực tế thay vì chỉ dựa vào ví dụ trong tài liệu.
4. Day 4.2: Truy vấn danh sách Content Items
Endpoint lấy một item phù hợp khi đã biết GUID hoặc path. Nhưng khi cần lấy danh sách category, bài viết hoặc các node con, chúng ta sử dụng endpoint truy vấn nhiều item:
GET /umbraco/delivery/api/v2/content
Endpoint này hỗ trợ các tham số như fetch, filter, sort, skip, take, expand và fields.
4.1. Lấy các node con của Bookstore Home
Để lấy các node con trực tiếp của Bookstore Home, sử dụng selector fetch=children: và truyền GUID hoặc path của node cha.
GET /umbraco/delivery/api/v2/content?fetch=children:YOUR-BOOKSTORE-HOME-GUID
Hãy thay placeholder bằng GUID thật của Bookstore Home.
Nếu Lịch sử và Triết học là hai node con trực tiếp của Bookstore Home và cả hai đã publish, chúng là những nội dung mà bạn mong đợi sẽ tìm thấy trong kết quả truy vấn.
children chỉ lấy các node con trực tiếp. Nếu cần lấy toàn bộ node ở các cấp sâu hơn, hãy tìm hiểu selector descendants.
4.2. Ví dụ response dạng danh sách
Endpoint truy vấn nhiều item trả về một cấu trúc danh sách có tổng số kết quả và các item. JSON dưới đây là ví dụ rút gọn, không phải dữ liệu được sao chép từ project thực tế.
{
"total": 2,
"items": [
{
"name": "Lịch sử",
"contentType": "bookCategory",
"id": "EXAMPLE-HISTORY-GUID",
"route": {
"path": "/lich-su/"
},
"properties": {
"categoryTitle": "Sách Lịch Sử"
}
},
{
"name": "Triết học",
"contentType": "bookCategory",
"id": "EXAMPLE-PHILOSOPHY-GUID",
"route": {
"path": "/triet-hoc/"
},
"properties": {
"categoryTitle": "Sách Triết Học"
}
}
]
}
Các GUID và route trong ví dụ chỉ nhằm minh họa. Response thực tế phụ thuộc vào GUID, alias, route và property được cấu hình trong project.
4.3. Nếu API không trả về kết quả như mong đợi
Hãy kiểm tra theo thứ tự:
- Bookstore Home và các category đã publish chưa?
- GUID truyền vào có đúng không?
- Các category có thực sự là node con trực tiếp của Bookstore Home không?
- Content Delivery API đã được bật chưa?
- Nếu vừa bật API, đã rebuild
DeliveryApiContentIndexchưa? - Nếu API đang được bảo vệ, request đã gửi đúng API key chưa?
Umbraco sử dụng DeliveryApiContentIndex cho endpoint truy vấn nhiều content item. Sau khi bật Content Delivery API lần đầu, hãy mở Examine Management trong Backoffice và rebuild index này để API có thể truy vấn nội dung đã được index.
5. Day 4.3: Các tham số truy vấn quan trọng
Content Delivery API hỗ trợ nhiều tham số để giới hạn, sắp xếp và mở rộng dữ liệu. Ta sẽ thực hành các tham số thường gặp trước khi tìm hiểu những truy vấn phức tạp hơn.
5.1. Phân trang với skip và take
skip là số item bỏ qua; take là số item tối đa muốn lấy trong request.
GET /umbraco/delivery/api/v2/content?fetch=children:YOUR-BOOKSTORE-HOME-GUID&skip=0&take=10
Ví dụ trên lấy tối đa 10 node con đầu tiên. Nếu có nhiều hơn 10 kết quả, bạn có thể thay đổi skip để lấy nhóm tiếp theo.
Đối với một danh sách có nhiều trang, hãy kiểm tra cả trường total trong response để biết tổng số kết quả mà API báo cáo.
5.2. Sắp xếp với sort
Tham số sort cho phép sắp xếp kết quả theo các tiêu chí được hỗ trợ, chẳng hạn tên hoặc thứ tự node trong Content Tree.
GET /umbraco/delivery/api/v2/content?fetch=children:YOUR-BOOKSTORE-HOME-GUID&sort=sortOrder:asc
sortOrder:asc là ví dụ sắp xếp tăng dần theo thứ tự nội dung. API hỗ trợ các lựa chọn sort cụ thể được mô tả trong tài liệu Umbraco; không phải mọi property tùy chỉnh đều tự động có thể dùng làm tiêu chí sort.
5.3. Lọc với filter
Tham số filter có thể được dùng để giới hạn kết quả theo Document Type hoặc các tiêu chí được API hỗ trợ.
GET /umbraco/delivery/api/v2/content?filter=contentType:bookCategory&sort=sortOrder:asc
Trong ví dụ này, bookCategory là alias minh họa của Document Type. Hãy thay bằng alias thực tế nếu project của bạn sử dụng tên khác.
Bạn cũng có thể kết hợp nhiều filter bằng cách lặp lại tham số filter. Các filter phải cùng được thỏa mãn để một item được đưa vào kết quả.
5.4. Mở rộng dữ liệu tham chiếu với expand
Một số property như Content Picker, Media Picker, Multinode Treepicker và các block editor có thể tham chiếu đến nội dung hoặc media khác. Mặc định, các property này không nhất thiết trả về đầy đủ thông tin của đối tượng được tham chiếu.
Để mở rộng một property có alias categoryImage, có thể dùng:
GET /umbraco/delivery/api/v2/content?fetch=children:YOUR-BOOKSTORE-HOME-GUID&expand=properties[categoryImage]
Thay categoryImage bằng alias thật của property đang dùng. Việc expansion chỉ áp dụng cho các property editor được hỗ trợ.
Nếu muốn mở rộng nhiều property, có thể liệt kê alias trong dấu ngoặc vuông. Ví dụ:
GET /umbraco/delivery/api/v2/content?expand=properties[categoryImage,relatedBooks]
Expansion có thể làm response lớn hơn. Chỉ nên mở rộng những dữ liệu mà ứng dụng thực sự cần.
5.5. Giới hạn property trả về với fields
Nếu chỉ cần một số property, bạn có thể dùng fields để giảm lượng dữ liệu trả về. Ví dụ chỉ lấy hai property có alias categoryTitle và categoryImage:
GET /umbraco/delivery/api/v2/content?fields=properties[categoryTitle,categoryImage]
Cú pháp trên minh họa cách giới hạn property. Khi dùng trong project, hãy kết hợp với query phù hợp và xác minh response để bảo đảm những trường cần thiết vẫn được trả về.
Phân biệt: expand mở rộng thông tin của các đối tượng được tham chiếu; fields giới hạn những trường được đưa vào response. Hai tham số này có thể được kết hợp khi cần.
6. Bảo mật Content Delivery API với API Key
Khi bật Content Delivery API, nội dung đã publish có thể được cung cấp công khai theo cấu hình mặc định. Nếu muốn giới hạn quyền truy cập, Umbraco hỗ trợ cấu hình PublicAccess và ApiKey.
6.1. Cấu hình ví dụ
Ví dụ sau minh họa cách bật API và yêu cầu API key. Chỉ áp dụng cấu hình này khi project thực sự cần bảo vệ endpoint; hãy kiểm tra cấu hình hiện tại trước khi thay đổi.
{
"Umbraco": {
"CMS": {
"DeliveryApi": {
"Enabled": true,
"PublicAccess": false,
"ApiKey": "replace-with-a-secret-key"
}
}
}
}
replace-with-a-secret-key là placeholder, không phải key thật. Trong môi trường thực tế, hãy lưu secret bằng cơ chế cấu hình an toàn phù hợp với môi trường triển khai, tránh commit key thật vào Git.
6.2. Gửi API key trong request
Khi API được cấu hình yêu cầu key, request cần có header Api-Key:
GET /umbraco/delivery/api/v2/content
Api-Key: YOUR_SECRET_API_KEY
Nếu thiếu key hoặc gửi key không hợp lệ, request có thể bị từ chối. Không nên đưa API key bí mật vào JavaScript chạy trên trình duyệt, biến môi trường public hoặc file Frontend được phân phối cho người dùng.
Ví dụ với Next.js, biến có tiền tố NEXT_PUBLIC_ được đưa ra phía client và không phù hợp để lưu secret. Nếu cần dùng key bí mật, request phải được thực hiện qua môi trường server-side được bảo vệ.
Lưu ý: Không phải mọi website đều cần bật bảo vệ API key. Nếu dữ liệu được chủ đích cung cấp công khai cho trình duyệt, hãy cân nhắc kiến trúc và phạm vi nội dung trước khi bật chế độ yêu cầu key.
7. Các lỗi thường gặp khi thực hành
7.1. API trả về 404
- GUID hoặc path không đúng.
- Content item chưa publish hoặc không tồn tại trong phạm vi truy vấn.
- Route path không khớp với cấu hình của website.
7.2. API trả về 401 Unauthorized
- API đang yêu cầu API key nhưng request không gửi header
Api-Key. - API key gửi lên không khớp với cấu hình hiện tại.
7.3. Endpoint danh sách không trả về dữ liệu mới
- Kiểm tra nội dung đã publish chưa.
- Kiểm tra cấu hình Delivery API.
- Nếu vừa bật API, kiểm tra và rebuild
DeliveryApiContentIndex. - Kiểm tra selector, filter và GUID được truyền vào.
7.4. Property không xuất hiện như mong đợi
- Kiểm tra alias property trên Document Type.
- Kiểm tra property đã được nhập dữ liệu và publish chưa.
- Kiểm tra property editor có hỗ trợ expansion nếu đang dùng
expand. - Kiểm tra tham số
fieldscó vô tình loại bỏ property cần thiết hay không.
8. Bài tập thực hành
Hãy thực hiện các bài tập sau trên project Bookstore của bạn:
- Gọi endpoint lấy Bookstore Home bằng GUID thật.
- Ghi lại giá trị
name,contentType,idvàroute.pathtừ response thực tế. - Gọi endpoint
/content?fetch=children:...để lấy category con. - Xác minh danh sách trả về có Lịch sử và Triết học hay không.
- Thử thêm
skip=0&take=10. - Thử lọc theo alias Document Type thực tế.
- Nếu category có Content Picker hoặc Media Picker, thử
expandtrên property tương ứng. - Ghi lại một lỗi gặp phải và cách bạn xác định nguyên nhân.
9. Tổng kết Day 4
Sau bài viết này, bạn cần nắm được các điểm chính:
- Lấy một item: dùng
/umbraco/delivery/api/v2/content/item/{id}hoặc endpoint theo path. - Lấy nhiều item: dùng
/umbraco/delivery/api/v2/content. - Truy vấn theo cấu trúc: dùng
fetch=children:...hoặcfetch=descendants:.... - Phân trang: dùng
skipvàtake. - Sắp xếp và lọc: dùng các giá trị
sortvàfilterđược API hỗ trợ. - Điều chỉnh response: dùng
expandđể mở rộng property tham chiếu vàfieldsđể giới hạn dữ liệu. - Bảo mật: cấu hình
PublicAccessvàApiKeyphù hợp với yêu cầu của hệ thống.
Quan trọng nhất, hãy phân biệt giữa JSON minh họa và response thật của project. Khi thực hành, luôn kiểm tra GUID, alias, route và dữ liệu đã publish thay vì sao chép nguyên các giá trị ví dụ.
10. Chuẩn bị cho Day 5: Multilingual trong Umbraco
Project tiếp theo của chúng ta cần hỗ trợ nhiều ngôn ngữ như Vietnamese, English, Cantonese, Mandarin và French. Vì vậy, bước kế tiếp là tìm hiểu cơ chế đa ngôn ngữ có sẵn trong Umbraco trước khi thiết kế database và custom API riêng.
Ở Day 5, chúng ta sẽ tìm hiểu:
- Culture, language code và cách cấu hình Languages trong Umbraco.
- Language Variants và cách lưu nội dung theo từng ngôn ngữ.
- Cách publish và truy vấn nội dung theo ngôn ngữ.
- Cách dùng header
Accept-Languagekhi gọi Content Delivery API bằng GUID. - Phân biệt nội dung CMS đa ngôn ngữ với dữ liệu nghiệp vụ cần quản lý bằng database và custom API.
Đây sẽ là nền tảng để xây dựng hệ thống multilingual có thể mở rộng ngôn ngữ mà không phải viết logic riêng cho từng ngôn ngữ.
Nhận xét