Tham chiếu API
Địa chỉ gốc: https://api.i-catholic.org/v2/public/cms/{siteSlug}. Có đúng bốn đường dẫn:
| Phương thức | Đường dẫn | Dùng để |
|---|---|---|
GET | /site | Thông tin trang web, ngôn ngữ, danh mục, thẻ, menu |
GET | /entries | Danh sách bài viết (lọc theo danh mục, thẻ, tìm kiếm, «Đọc nhiều») |
GET | /entries/{entrySlug} | Một bài viết hoặc một trang |
POST | /entries/{entrySlug}/view | Tín hiệu đếm một lượt xem |
Quy tắc chung:
- Không cần xác thực. API bỏ qua mọi header
Authorization; gửi token cũng không làm thay đổi kết quả. - Tham số là tập đóng. Một tham số không có trong bảng của đường dẫn đó bị từ chối với
400(ví dụ?preview=1). siteSlug: chữ thườnga-z, số và-, 1–64 ký tự.entrySlug: chữ thường và số, nối bằng một dấu-(ví dụle-bon-mang), tối đa 120 ký tự. Slug sai dạng nhận về cùng404như slug không tồn tại.- Dữ liệu trả về không bao giờ chứa mã số nội bộ, trạng thái, tác giả hay bản nháp.
Lấy thông tin trang web
GET /v2/public/cms/{siteSlug}/site?locale=vi
| Tham số | Bắt buộc | Giá trị |
|---|---|---|
locale | không | vi, en, es, pt, fr, it. Bỏ trống thì dùng ngôn ngữ chính của trang web. Nên luôn ghi rõ (xem cache). |
Phản hồi 200, dạng { data: PublicCmsSite }:
| Trường | Kiểu | Ghi chú |
|---|---|---|
slug | string | Mã trang web. |
primaryLocale | string | Ngôn ngữ chính. |
locales | string[] | Các ngôn ngữ đã bật. Chỉ những ngôn ngữ này được phục vụ. |
locale | string | Ngôn ngữ mà khối info thực sự được trả về (xem Đa ngôn ngữ). |
info | object | null | Thông tin đơn vị. null khi nhân sự chưa từng lưu thông tin: hãy có nội dung dự phòng. |
categories | object[] | Mọi danh mục, theo thứ tự cây: mỗi danh mục cấp 1, rồi các con của nó. |
tags | object[] | Mọi thẻ, xếp theo tên. Bài viết chỉ mang slug của thẻ; tên thẻ đọc ở đây. |
menus | object | Luôn có primary và footer (mảng, có thể rỗng). |
info (chuỗi văn bản thuần, không phải HTML; hãy in ra như văn bản):
| Trường | Kiểu |
|---|---|
name | string (luôn có nội dung) |
shortName, legalName, tagline, motto, mottoRef, description, address, email, copyright | string (có thể rỗng) |
phones | string[] (tối đa 5) |
officeHours | string[] (tối đa 10 dòng) |
mapEmbedUrl | string | null. Khi có, luôn là một địa chỉ nhúng Google Maps (https://www.google.com/maps… hoặc https://maps.google.com/…), dùng làm src của <iframe>. |
Danh mục { slug, parent, name, position }: parent là slug của danh mục cha hoặc null; cây có tối đa hai cấp. Thẻ { slug, name }.
Mục menu:
| Trường | Kiểu | Ghi chú |
|---|---|---|
label | string | Nhãn hiển thị. |
kind | entry | term | url | Mục trỏ tới đâu. |
slug | string | Với entry và term. |
entryType | post | page | Với entry. |
category | string | Với entry là bài viết: slug danh mục chính, để bạn dựng đường dẫn đúng chuyên mục. |
taxonomy | category | tag | Với term. |
url | string | Với url: hoặc đường dẫn trong trang web của bạn bắt đầu bằng /, hoặc một địa chỉ https:// đầy đủ. |
children | object[] | Mục con (menu tối đa hai cấp). |
Mục entry và term không có sẵn đường dẫn: bạn tự dựng đường dẫn theo cấu trúc trang web của mình từ slug (ví dụ /trang/{slug} cho trang, /tin-tuc/{slug} cho bài, /tin-tuc?category={slug} cho danh mục). Mục trỏ tới nội dung đã gỡ, chưa xuất bản hay không có bản dịch phù hợp đã được bỏ sẵn khỏi menu (cùng các mục con).
function menuHref(item: MenuItem): string {
switch (item.kind) {
case 'entry':
return item.entryType === 'page' ? `/trang/${item.slug}` : `/tin-tuc/${item.slug}`
case 'term':
return `/tin-tuc?${item.taxonomy === 'tag' ? 'tag' : 'category'}=${encodeURIComponent(item.slug!)}`
case 'url':
return item.url! // starts with "/" (your site) or "https://" (external)
}
}
Lỗi: 404 (trang web không có, chưa bật, ngôn ngữ chưa bật), 400 (locale ngoài sáu ngôn ngữ, tham số lạ), 429.
Lấy danh sách bài viết
GET /v2/public/cms/{siteSlug}/entries?locale=vi&page=1&limit=12
Chỉ trả về bài viết (post) đã xuất bản và có bản dịch đúng ngôn ngữ locale. Trang tĩnh (page) không bao giờ nằm trong danh sách.
| Tham số | Bắt buộc | Giá trị |
|---|---|---|
locale | có | Một trong các ngôn ngữ đã bật của trang web. |
category | không | Slug danh mục. Danh mục cha bao gồm cả bài của danh mục con. |
tag | không | Slug thẻ. |
q | không | Từ khóa tìm kiếm, 2–100 ký tự sau khi cắt khoảng trắng. Xem Tìm kiếm. |
sort | không | Chỉ nhận popular («Đọc nhiều»): khi đó page phải là 1 và limit là 3, 6 hoặc 12. |
page | có | Số nguyên 1–100000. |
limit | có | Đúng một trong 3, 6, 12, 24, 100. |
category, tag, q, sort loại trừ nhau: gửi hai cái trở lên nhận 400 với message: "CMS_FILTER_CONFLICT". Viết tham số theo thứ tự locale, category, tag, q, sort, page, limit.
Thứ tự kết quả (khi không tìm kiếm và không sort): các bài nổi bật của chính danh sách đó đứng đầu (theo thứ tự nhân sự sắp, tối đa 10), sau đó là bài mới nhất theo publishedAt. Danh sách chung (không lọc) dùng bài nổi bật của trang chủ; danh sách theo danh mục dùng bài nổi bật của danh mục đó; danh sách theo thẻ không có bài nổi bật.
Nhân sự có thể đánh dấu một loại nội dung là không liệt kê (ví dụ một loại chỉ dùng cho mục riêng). Bài của loại đó không xuất hiện trong danh sách chung, «Đọc nhiều» và kết quả tìm kiếm, nhưng vẫn xuất hiện trong danh sách theo danh mục, theo thẻ, và mở được theo slug.
Phản hồi 200:
{
"data": [
{
"slug": "le-bon-mang",
"category": "tin-tuc",
"categories": ["tin-tuc"],
"tags": ["gioi-tre"],
"title": "Thánh lễ Bổn mạng",
"excerpt": "Đoạn tóm tắt ngắn…",
"publishedAt": "2026-10-12T01:30:00.000Z",
"featured": true,
"cover": { "url": "https://…/anh-bia.webp", "alt": "Cộng đoàn dâng lễ" },
"locale": "vi",
"contentType": null,
"meta": {}
}
],
"meta": { "page": 1, "limit": 12, "total": 37, "pageCount": 4 }
}
Mục trong danh sách không có trường type: mọi mục đều là bài viết.
| Trường | Kiểu | Ghi chú |
|---|---|---|
slug | string | |
category | string | Slug danh mục chính. |
categories | string[] | Mọi danh mục của bài. |
tags | string[] | Slug các thẻ; tên đọc ở /site. |
title, excerpt | string | Văn bản thuần. excerpt có thể rỗng. |
publishedAt | string | ISO 8601, giờ UTC. Hiển thị theo múi giờ của bạn. |
featured | boolean | Nổi bật trong danh sách này. Luôn false khi tìm kiếm và «Đọc nhiều». |
cover | object | null | Ảnh bìa { url, alt }; url là địa chỉ https:// đầy đủ, alt có thể rỗng. |
locale | string | Luôn bằng locale bạn hỏi. |
contentType | string | null | Slug loại nội dung; null với bài thường. |
meta | object | Trường tùy chỉnh. Xem Trường tùy chỉnh. |
meta của danh sách: { page, limit, total, pageCount }. Một trang vượt quá pageCount trả về data rỗng. Với sort=popular, total là số mục thực trả về.
Lỗi: 404 (trang web/ngôn ngữ như trên, hoặc slug danh mục/thẻ không tồn tại), 400 (thiếu locale/page/limit, limit ngoài danh sách, CMS_FILTER_CONFLICT, CMS_SEARCH_QUERY_INVALID, CMS_POPULAR_QUERY_INVALID, tham số lạ), 429.
Lấy một entry
GET /v2/public/cms/{siteSlug}/entries/{entrySlug}?locale=vi
| Tham số | Bắt buộc | Giá trị |
|---|---|---|
locale | có | Một ngôn ngữ đã bật. Entry phải có bản dịch đúng ngôn ngữ này, nếu không là 404. |
Trả về bài viết hoặc trang. Ngoài mọi trường của mục danh sách, có thêm:
| Trường | Kiểu | Ghi chú |
|---|---|---|
type | post | page | |
category | string | null | null với trang (trang không có danh mục, categories và tags là []). |
bodyHtml | string | Nội dung HTML. |
seo | object | { title, description, auto }. |
featured | boolean | Ở đây là cờ nổi bật của danh sách trang chủ. |
slug trong phản hồi có thể khác slug bạn hỏi: khi nhân sự đổi slug, slug cũ vẫn trả 200 với entry hiện tại. Xem Slug cũ.
seo: nếu nhân sự không nhập, máy chủ tự tạo khi đọc: title từ tiêu đề (cắt ở 70 ký tự), description từ tóm tắt hoặc thân bài (cắt ở 160 ký tự, theo từ); khi đó auto là true. Trong thực tế cả hai luôn là chuỗi, nhưng kiểu khai báo cho phép null, nên hãy dự phòng.
bodyHtml đã được máy chủ lọc theo danh sách cho phép:
- thẻ:
p br strong b em i u a ul ol li h2 h3 blockquote hr img; a: chỉhrefdạnghttp:,https:,mailto:, luôn kèmrel="noopener noreferrer";img: chỉsrcdạnghttps://vàalt;- không có
style,class,id,on*hay bất kỳ thuộc tính nào khác.
Dù vậy, hãy lọc lại ở phía bạn (ví dụ DOMPurify với cùng danh sách) trước khi chèn bằng innerHTML / dangerouslySetInnerHTML: đừng tin tuyệt đối một phản hồi mạng. Đây cũng là chỗ tốt để thêm loading="lazy" cho ảnh và target="_blank" cho liên kết ra ngoài. Ảnh trong thân bài có thể nằm trên bất kỳ máy chủ https nào; nếu trang của bạn có Content Security Policy, hãy cho phép img-src https:.
Lỗi: 404 (trang web/ngôn ngữ như trên, entry không có, chưa xuất bản, hẹn giờ chưa tới, đã xóa, hoặc không có bản dịch ngôn ngữ này), 400 (thiếu hoặc sai locale, tham số lạ), 429.
Gửi tín hiệu lượt xem
POST /v2/public/cms/{siteSlug}/entries/{entrySlug}/view
Không tham số, không thân yêu cầu, không header. Luôn trả 204 không có nội dung, kể cả khi lượt đó không được đếm. Cách gọi đúng và quy tắc đếm: Lượt xem.
Dạng lỗi
Mọi lỗi có cùng dạng:
{
"statusCode": 400,
"errorCode": "VALIDATION_ERROR",
"message": "limit must be one of the following values: 3, 6, 12, 24, 100",
"timestamp": "2026-10-19T12:34:26.516Z",
"requestId": "oaf24ltjxmpxia9x4dedtn4b"
}
statusCode | errorCode | message |
|---|---|---|
| 404 | NOT_FOUND | Luôn đúng "Not found". Không phân biệt được trang web sai, nội dung không có hay ngôn ngữ chưa bật. |
| 400 | VALIDATION_ERROR | Một mã như CMS_FILTER_CONFLICT, CMS_SEARCH_QUERY_INVALID, CMS_POPULAR_QUERY_INVALID, hoặc câu mô tả lỗi tham số (nhiều lỗi nối bằng ; ). |
| 429 | RATE_LIMITED | Vượt giới hạn tần suất. Xem Giới hạn. |
| 5xx | ví dụ INTERNAL_ERROR | Lỗi phía máy chủ; thử lại sau. |
Hãy rẽ nhánh theo statusCode và (với 400) theo message; ghi lại requestId khi báo lỗi cho chúng tôi.