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

Umbraco 13: Làm chủ Content Delivery API - Day 4

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.

flowchart TD A["Umbraco Backoffice"] --> B["Content Tree và nội dung"] B --> C["Content Delivery API"] C --> D["JSON Response"] D --> E["Next.js / React / Mobile App"]

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:

  1. Node Bookstore Home đã được tạo và publish.
  2. Hai category Lịch sử và Triết học đã được tạo dưới Bookstore Home.
  3. Các Document Type và property cần kiểm tra đã được cấu hình đúng.
  4. 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:

  1. Giá trị name có phải Bookstore Home không?
  2. contentType có khớp alias Document Type không?
  3. GUID trả về có đúng với node đang truy vấn không?
  4. route.path có đúng với route dự kiến không?
  5. 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ự:

  1. Bookstore Home và các category đã publish chưa?
  2. GUID truyền vào có đúng không?
  3. Các category có thực sự là node con trực tiếp của Bookstore Home không?
  4. Content Delivery API đã được bật chưa?
  5. Nếu vừa bật API, đã rebuild DeliveryApiContentIndex chưa?
  6. 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.

flowchart TD A["HTTP Request"] --> B["Content Delivery API"] B --> C["Fetch / Filter"] C --> D["Sort"] D --> E["Skip / Take"] E --> F["Expand / Fields"] F --> G["JSON Response"]

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ố fields có 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:

  1. Gọi endpoint lấy Bookstore Home bằng GUID thật.
  2. Ghi lại giá trị name, contentType, id và route.path từ response thực tế.
  3. Gọi endpoint /content?fetch=children:... để lấy category con.
  4. Xác minh danh sách trả về có Lịch sử và Triết học hay không.
  5. Thử thêm skip=0&take=10.
  6. Thử lọc theo alias Document Type thực tế.
  7. Nếu category có Content Picker hoặc Media Picker, thử expand trên property tương ứng.
  8. 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ặc fetch=descendants:....
  • Phân trang: dùng skip và take.
  • Sắp xếp và lọc: dùng các giá trị sort và 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 PublicAccess và ApiKey phù 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-Language khi 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ữ.

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.