Chuyển đến nội dung chính

Umbraco 13: Content Delivery API — Từ CMS đến Headless API - Day 4

Ở 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.

flowchart TD A["Editor"] --> B["Umbraco Backoffice"] B --> C["Content Tree"] C --> D["Published Content"] D --> E["Razor Template"] E --> F["HTML Response"] F --> G["Browser"]

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.

flowchart TD A["Editor"] --> B["Umbraco Backoffice"] B --> C["Published Content"] C --> D["Content Delivery API"] D --> E["JSON Response"] E --> F["Next.js / React"] F --> G["HTML giao diện website"] G --> H["Browser"]

Đ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_HERE bằ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 Header Api-Key chứ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:

  1. 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.
  2. Kiểm tra danh sách Endpoints: Swagger sẽ hiển thị danh sách các endpoint thuộc Content và 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:

  1. Mở node cần test trong Umbraco Backoffice (ví dụ: node History).
  2. Chuyển sang tab Info.
  3. 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/).
  4. Khi điền vào tham số path trên Swagger:
    • Bỏ dấu gạch chéo ở đầu và cuối: Nhập history thay vì /history/.
    • Đối với node con: Nhập history/vietnamese-history.

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}:

  1. Mở Endpoint: Chọn GET /umbraco/delivery/api/v2/content/item/{path} trong nhóm Content và nhấn nút Try it out.
  2. Nhập Parameters:
    • path (required): Nhập history (lấy từ mục Links trong tab Info).
    • Api-Key (header): Nhập API key đã cấu hình trong appsettings.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-us hoặc vi-vn).
    • fields (query): Giữ nguyên properties[$all] để lấy toàn bộ danh sách properties.
  3. Thực thi: Nhấn nút Execute.
  4. 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 path là / hoặc GUID tương ứng.
  • Node Triết học: Gọi endpoint GET /umbraco/delivery/api/v2/content/item/{path} với path là 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:

  1. Ứng dụng Umbraco có đang chạy không?
  2. Request có đúng giao thức và cổng không?
  3. Đường dẫn endpoint có đúng không?
  4. Content Delivery API đã được bật trong cấu hình chưa?
  5. Nếu sử dụng API key, request đã gửi header Api-Key tươ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ố fields hoặc expand là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:Enabled thành true.
  • Thêm PublicAccess: false và khai báo ApiKey.
  • 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 API trê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-Key và đườ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ớ:

  1. Umbraco quản lý nội dung: Document Types và Content Tree xác định cấu trúc dữ liệu.
  2. 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.
  3. 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.

Tài liệu tham khảo

Nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.