Ở các phần trước, chúng ta đã tìm hiểu Document Types, Properties, Data Types, Compositions và cách tổ chức nội dung trong Umbraco CMS. Đến Part 3, chúng ta đã xây dựng cấu trúc Content Tree cho website nhà sách chuyên về lịch sử và triết học.
Trong bài này, chúng ta sẽ tìm hiểu cách một ứng dụng khác lấy nội dung từ Umbraco mà không cần sử dụng Razor Template để render HTML trực tiếp.
Đây là bước đầu tiên để chuyển từ một website Umbraco truyền thống sang kiến trúc Headless CMS, trong đó Umbraco quản lý nội dung còn Next.js chịu trách nhiệm xây dựng giao diện người dùng.
Mục tiêu của bài viết:
- Hiểu Headless CMS và Content Delivery API.
- Phân biệt Traditional Rendering, Delivery API và Custom API.
- Bật Content Delivery API trên Umbraco 13.
- Thao tác trên giao diện Swagger UI (chọn API definition, truyền API Key, thực thi request).
- Gọi API và đọc JSON response.
- Kiểm tra nội dung Bookstore Home, Lịch sử và Triết học.
- Biết cách xử lý những lỗi thường gặp khi API không trả dữ liệu.
1. Từ Traditional CMS đến Headless CMS
1.1. Umbraco truyền thống hoạt động như thế nào?
Trong mô hình truyền thống, Umbraco vừa quản lý nội dung vừa có thể render giao diện website thông qua Razor Template.
Ví dụ, người biên tập tạo một danh mục sách có tên Lịch sử trong Backoffice. Khi khách truy cập URL tương ứng, Umbraco lấy nội dung đã publish, truyền dữ liệu cho Razor Template và tạo ra HTML trả về trình duyệt.
Trong mô hình này, Umbraco chịu trách nhiệm cả quản lý nội dung lẫn trình bày giao diện.
1.2. Headless CMS là gì?
Headless CMS tách phần quản lý nội dung khỏi phần giao diện hiển thị. CMS tập trung lưu trữ và cung cấp nội dung, còn frontend có thể được xây dựng bằng Next.js, React hoặc một công nghệ khác.
Với Umbraco 13, Content Delivery API cung cấp nội dung đã publish dưới dạng JSON để các ứng dụng frontend có thể sử dụng.
Điểm khác biệt quan trọng là Delivery API không trực tiếp tạo ra giao diện trang web hoàn chỉnh cho người dùng. API cung cấp dữ liệu; frontend quyết định cách trình bày dữ liệu đó.
1.3. Vai trò của từng thành phần
| Thành phần | Vai trò |
|---|---|
| Umbraco Backoffice | Nơi biên tập và quản lý nội dung. |
| Content Tree | Tổ chức quan hệ cha–con giữa các node. |
| Content Delivery API | Cung cấp nội dung CMS dưới dạng JSON. |
| Next.js | Lấy dữ liệu và xây dựng giao diện website. |
| Browser | Hiển thị trang web cuối cùng cho người dùng. |
2. Phân biệt Delivery API và Custom API
Trước khi thực hành, cần phân biệt hai loại API có thể xuất hiện trong một hệ thống sử dụng Umbraco.
2.1. Umbraco Content Delivery API
Đây là API có sẵn của Umbraco, được thiết kế để cung cấp nội dung CMS đã publish.
Ví dụ, website nhà sách có node Lịch sử với phần mô tả danh mục. Next.js có thể gọi Delivery API để lấy tên, đường dẫn và các properties được API trả về, sau đó render trang danh mục.
2.2. Custom API bằng ASP.NET Core
Custom API là endpoint do lập trình viên xây dựng để xử lý các yêu cầu nghiệp vụ riêng.
Ví dụ, nếu website cần tính tổng tiền giỏ hàng, kiểm tra tồn kho hoặc tạo đơn hàng, chúng ta có thể xây dựng API riêng bằng ASP.NET Core.
| Tiêu chí | Delivery API | Custom API |
|---|---|---|
| Mục đích | Cung cấp nội dung CMS. | Xử lý nghiệp vụ riêng. |
| Triển khai | Umbraco cung cấp sẵn. | Lập trình viên tự xây dựng. |
| Ví dụ | Lấy nội dung danh mục sách. | Tạo đơn hàng hoặc tính giá giỏ hàng. |
Trong Day 4, chúng ta chỉ thực hành Content Delivery API. Custom API sẽ được tìm hiểu ở phần sau.
3. Kiểm tra và bật Content Delivery API trong Umbraco 13
3.1. API có được tích hợp sẵn không?
Từ Umbraco 13, các dependency của Content Delivery API được đăng ký mặc định trong cấu hình khởi tạo Umbraco thông thường. Tuy nhiên, tính năng này vẫn cần được bật bằng cấu hình.
Vì vậy, không nên mặc định rằng API đã hoạt động chỉ vì project sử dụng Umbraco 13.
3.2. Mở file appsettings.json
Trong project ASP.NET Core chứa Umbraco, mở file appsettings.json ở thư mục gốc.
Kiểm tra cấu hình dưới đây:
{
"Umbraco": {
"CMS": {
"DeliveryApi": {
"Enabled": true
}
}
}
}
Nếu project đã có cấu hình Umbraco:CMS, hãy bổ sung section DeliveryApi vào cấu hình hiện tại thay vì ghi đè toàn bộ file.
Ý nghĩa:
DeliveryApi: khu vực cấu hình Content Delivery API.Enabled: true: bật tính năng Delivery API.
Lưu file và khởi động lại ứng dụng nếu cần để cấu hình mới được áp dụng.
3.3. Cấu hình bảo vệ API bằng API Key (Headless Setup)
Khi Delivery API được bật, mặc định nội dung đã publish sẽ được công khai. Nếu website của bạn hoạt động theo mô hình Headless chỉ cho phép Frontend (Next.js) truy xuất dữ liệu, bạn cần tắt truy cập công khai và thiết lập API Key:
{
"Umbraco": {
"CMS": {
"DeliveryApi": {
"Enabled": true,
"PublicAccess": false,
"ApiKey": "YOUR_SECRET_API_KEY_HERE"
}
}
}
}
Lưu ý quan trọng:
- Thay thế
YOUR_SECRET_API_KEY_HEREbằng một chuỗi bí mật ngẫu nhiên đủ dài và an toàn. - Khi
PublicAccess: false, bất kỳ request nào gửi tới Delivery API cũng bắt buộc phải đính kèm HeaderApi-Keychứa chuỗi secret tương ứng. - Không đưa API key bí mật này vào mã JavaScript chạy trên trình duyệt client-side hoặc khai báo trong biến môi trường Next.js có tiền tố
NEXT_PUBLIC_. Dùng nó ở phía Server Component hoặc API Routes của Next.js.
3.4. Thao tác trên giao diện Swagger UI
Trong môi trường Development, mở trình duyệt và truy cập địa chỉ Swagger:
https://localhost:PORT/umbraco/swagger
Khi giao diện Swagger hiển thị, hãy thực hiện các bước cấu hình sau:
- Chọn API Definition: Ở góc trên bên phải màn hình tại mục Select a definition, chọn
Umbraco Delivery API. - Kiểm tra danh sách Endpoints: Swagger sẽ hiển thị danh sách các endpoint thuộc
ContentvàMedia. Hãy sử dụng các endpoint thuộc v2.
4. Gọi thử Content Delivery API trên Swagger UI
4.1. Quy tắc xác định tham số `path` từ Backoffice (Quan trọng)
Để tránh gặp lỗi 404 Not Found khi gọi API theo đường dẫn, hãy luôn kiểm tra URL segment chính xác của node trước khi test:
- Mở node cần test trong Umbraco Backoffice (ví dụ: node History).
- Chuyển sang tab Info.
- Nhìn vào mục Links để xem đường dẫn được hệ thống sinh ra (ví dụ:
/history/hoặc/history/vietnamese-history/). - Khi điền vào tham số
pathtrên Swagger:- Bỏ dấu gạch chéo ở đầu và cuối: Nhập
historythay vì/history/. - Đối với node con: Nhập
history/vietnamese-history.
- Bỏ dấu gạch chéo ở đầu và cuối: Nhập
4.2. Hướng dẫn các bước gọi API từng bước trên Swagger
Dưới đây là từng bước chi tiết để test thành công endpoint GET /umbraco/delivery/api/v2/content/item/{path}:
- Mở Endpoint: Chọn
GET /umbraco/delivery/api/v2/content/item/{path}trong nhóm Content và nhấn nút Try it out. - Nhập Parameters:
path(required): Nhậphistory(lấy từ mục Links trong tab Info).Api-Key(header): Nhập API key đã cấu hình trongappsettings.json(ví dụ:e9f8a2b1-4c3d-4e5f-8a9b-123456789abc).Accept-Language(header - optional): Nhập mã ngôn ngữ nếu site có đa ngôn ngữ (ví dụ:en-ushoặcvi-vn).fields(query): Giữ nguyênproperties[$all]để lấy toàn bộ danh sách properties.
- Thực thi: Nhấn nút Execute.
- Phân tích Response thành công (Code 200):
{ "contentType": "bookCategory", "name": "History", "createDate": "2026-10-17T23:02:19.997Z", "updateDate": "2026-10-17T23:21:28.187Z", "route": { "path": "/history/", "startItem": { "id": "256048db-162d-4cc7-b7e3-c4537fb970bd", "path": "bookstore-trang-chu" } }, "id": "c53b36be-22d1-453b-9403-754dee12a4dd", "properties": { "categoryTitle": "History", "categoryDescription": null }, "cultures": {} }
4.3. Gọi nội dung các node thực tế
Bạn có thể lặp lại các bước trên cho các route khác của nhà sách:
- Node Trang chủ (Bookstore Home): Gọi với
pathlà/hoặc GUID tương ứng. - Node Triết học: Gọi endpoint
GET /umbraco/delivery/api/v2/content/item/{path}vớipathlàtriết-hoc.
Đừng vội chuyển sang viết code Next.js nếu chưa test thành công trên Swagger UI và đảm bảo API Key hoạt động chính xác.
5. Đọc JSON response
5.1. Ví dụ response minh họa
Giả sử Delivery API trả về dữ liệu của một node danh mục sách như sau. Đây là JSON minh họa để giải thích cấu trúc, không phải response được chép trực tiếp từ project:
{
"contentType": "bookCategory",
"name": "Lịch sử",
"route": {
"path": "/lich-su/",
"startItem": {
"id": "00000000-0000-0000-0000-000000000001",
"path": ""
}
},
"id": "00000000-0000-0000-0000-000000000002",
"properties": {
"categoryTitle": "Lịch sử",
"categoryDescription": "Khám phá lịch sử Việt Nam và thế giới."
}
}
Các GUID và property trong ví dụ được tạo để minh họa. Chúng không đại diện cho dữ liệu thực tế của website nhà sách.
5.2. Ý nghĩa các trường
| Trường | Ý nghĩa |
|---|---|
contentType |
Alias của Document Type, ví dụ bookCategory. |
name |
Tên content item trong Umbraco. |
route.path |
Đường dẫn nội dung được API cung cấp. |
id |
GUID của content item. |
properties |
Các property được serialize từ nội dung. |
Trong response thực tế, API còn có thể trả về các trường khác như thời gian tạo và cập nhật. Một số property có cấu trúc lồng nhau hoặc cần dùng tham số expand để lấy thêm thông tin liên quan.
5.3. Vì sao alias và tên property quan trọng?
Trong Umbraco, tên Document Type hiển thị cho người biên tập không nhất thiết giống alias mà API trả về.
Ví dụ:
- Tên hiển thị:
Book Category. - Alias:
bookCategory. - Property hiển thị:
Category Description. - Alias property:
categoryDescription.
Alias thực tế phụ thuộc vào cấu hình project. Vì vậy, khi đọc JSON, hãy kiểm tra chính xác tên trường thay vì tự suy đoán từ nhãn hiển thị trong Backoffice.
5.4. Content Tree có tự động xuất hiện đầy đủ trong JSON không?
Không nên giả định rằng gọi một content item sẽ tự động trả về toàn bộ cây nội dung con theo dạng đệ quy.
Delivery API có endpoint lấy một item và endpoint truy vấn nhiều items. Cách lấy dữ liệu con phụ thuộc endpoint, tham số truy vấn và cấu trúc properties.
Ví dụ, nếu cần hiển thị danh sách sách bên trong một danh mục, trước hết hãy xác định dữ liệu nào có trong response hiện tại và endpoint nào phù hợp để truy vấn thêm các sách đó.
6. Content Delivery API và Razor Template khác nhau như thế nào?
Ở Part 3, chúng ta đã sử dụng Razor để duyệt các node con:
var categories = Model.Children()
.Where(x => x.ContentType.Alias == "bookCategory");
Đoạn code trên chạy trong Razor Template của ứng dụng Umbraco. Nó đọc các node con từ model nội dung đã publish và lọc theo alias Document Type.
Trong khi đó, khi sử dụng Content Delivery API, ứng dụng frontend gửi HTTP request để lấy dữ liệu JSON.
| Razor | Content Delivery API |
|---|---|
| Chạy phía server Umbraco. | Được gọi thông qua HTTP. |
| Làm việc với model nội dung trong Razor. | Trả dữ liệu theo cấu trúc JSON. |
| Có thể render HTML trực tiếp. | Frontend dùng dữ liệu để render HTML. |
Hai cách tiếp cận không loại trừ nhau. Một hệ thống có thể sử dụng Traditional Rendering cho một số trang và Delivery API cho ứng dụng frontend riêng.
7. Debug các lỗi thường gặp
7.1. Không truy cập được endpoint
Kiểm tra lần lượt:
- Ứng dụng Umbraco có đang chạy không?
- Request có đúng giao thức và cổng không?
- Đường dẫn endpoint có đúng không?
- Content Delivery API đã được bật trong cấu hình chưa?
- Nếu sử dụng API key, request đã gửi header
Api-Keytương ứng chưa?
7.2. Nhận HTTP 404 Not Found
Một số nguyên nhân thường gặp:
- Content item chưa được publish.
- Đường dẫn truyền vào không khớp với route thực tế.
- Content item không tồn tại hoặc không được API trả về theo cấu hình hiện tại.
- Request sử dụng sai endpoint.
Hãy mở node trong Backoffice, kiểm tra trạng thái publish và đường dẫn, sau đó thử lại request. Nếu API trả về thông tin lỗi, hãy đọc response body để biết thêm chi tiết.
7.3. API trả về dữ liệu nhưng thiếu property
Không phải mọi property đều nhất thiết xuất hiện theo dạng đơn giản. Kiểm tra:
- Property đã được tạo và lưu đúng trong Document Type chưa?
- Node đã được publish sau khi cập nhật nội dung chưa?
- Alias property có chính xác không?
- Property editor có cấu trúc dữ liệu đặc biệt không?
- Request có sử dụng tham số
fieldshoặcexpandlàm giới hạn response không?
7.4. Đã bật Delivery API nhưng endpoint danh sách chưa phản ánh nội dung mới
Umbraco 13 sử dụng Delivery API content index cho endpoint truy vấn nhiều content items. Theo tài liệu chính thức, sau khi bật Delivery API, cần rebuild index DeliveryApiContentIndex để endpoint danh sách có thể phục vụ nội dung mới nhất.
Trong môi trường Development, hãy kiểm tra Examine Management trong Backoffice và trạng thái index nếu endpoint danh sách không hoạt động như mong đợi.
Đừng nhầm việc rebuild index của endpoint danh sách với việc mọi endpoint đều bắt buộc phải truy vấn index theo cùng một cách.
7.5. Phân biệt lỗi API và lỗi frontend
Ở Day 4, hãy gọi API trực tiếp bằng Swagger, trình duyệt hoặc công cụ HTTP trước khi đưa dữ liệu vào Next.js.
Nếu request trực tiếp đã thất bại, hãy debug ở phía Umbraco. Nếu request thành công và JSON hợp lệ nhưng giao diện Next.js không hiển thị, khi đó mới kiểm tra code frontend, cách đọc properties và xử lý response.
8. Thực hành tổng hợp với website nhà sách
Bài tập 1: Bật Delivery API và cấu hình API Key
- Mở
appsettings.json. - Cấu hình
Umbraco:CMS:DeliveryApi:Enabledthànhtrue. - Thêm
PublicAccess: falsevà khai báoApiKey. - Khởi động lại ứng dụng và kiểm tra trạng thái chạy.
Bài tập 2: Thử nghiệm trên Swagger UI
- Mở địa chỉ Swagger và chọn
Umbraco Delivery APItrên dropdown góc phải. - Thực hiện Try it out endpoint
GET /umbraco/delivery/api/v2/content/item/{path}. - Điền Header
Api-Keyvà đường dẫn của node Trang chủ hoặc Danh mục. - Lưu lại JSON response thực tế thu được.
Bài tập 3: Gọi API của Lịch sử và Triết học
- Kiểm tra hai node đã publish.
- Xác định đường dẫn chính xác của từng node.
- Gọi API cho từng danh mục qua Swagger.
- So sánh alias Document Type và các property trong response.
- Ghi lại sự khác nhau giữa JSON thực tế và ví dụ minh họa trong bài.
Bài tập 4: Tự debug một lỗi
Thử gọi một đường dẫn không tồn tại hoặc nhập sai API Key trên Swagger. Quan sát HTTP status (401, 404) và response body.
Không thay đổi dữ liệu production chỉ để tạo lỗi thử nghiệm.
9. Checklist hoàn thành Day 4
Trước khi chuyển sang Day 5, hãy xác nhận bạn có thể tự thực hiện các việc sau:
- Giải thích Headless CMS khác Traditional Rendering như thế nào.
- Giải thích vai trò của Content Delivery API.
- Phân biệt Delivery API và Custom API.
- Kiểm tra cấu hình bật Delivery API và thiết lập API Key trong Umbraco 13.
- Thao tác chọn definition và gửi request thành công trên Swagger UI.
- Gọi được API cho một content item đã publish.
- Đọc được các trường quan trọng trong JSON response thực tế.
- Giải thích vì sao alias Document Type và property phải khớp với cấu hình.
- Biết kiểm tra endpoint, trạng thái publish, API key và index khi có lỗi.
10. Tổng kết và bước tiếp theo
Trong Day 4, chúng ta đã chuyển từ việc tổ chức nội dung trong Umbraco Backoffice sang việc truy xuất nội dung thông qua Content Delivery API.
Ba ý quan trọng cần ghi nhớ:
- Umbraco quản lý nội dung: Document Types và Content Tree xác định cấu trúc dữ liệu.
- Delivery API cung cấp dữ liệu: API trả nội dung dưới dạng JSON, theo endpoint và cấu hình tương ứng.
- Frontend chịu trách nhiệm hiển thị: Next.js có thể sử dụng JSON để tạo trang chủ, trang danh mục và trang chi tiết sách.
Ở Day 5, chúng ta sẽ bắt đầu kết nối Umbraco với Next.js bằng App Router. Chúng ta sẽ cấu hình URL API qua biến môi trường, gọi API từ Server Component, khai báo TypeScript types và hiển thị dữ liệu Bookstore Home trên giao diện website.
Nhận xét