Hướng dẫn tạo Todo List với API Key trong NocoBase
Nguồn: AlbertMa, Viết bởi: Huy Hoàng
Trong bài viết này, tôi sẽ hướng dẫn bạn từng bước cách sử dụng API Key trong NocoBase để truy xuất dữ liệu, thông qua ví dụ To-Do List nhằm giúp bạn hiểu rõ từng chi tiết trong quá trình thực hiện.
1. Tìm hiểu khái niệm về API Keys
Trước khi bắt đầu, chúng ta cần hiểu rõ một câu hỏi quan trọng: API Key là gì?
API Key hoạt động giống như một tấm vé thông hành, dùng để xác thực xem một yêu cầu (request) gửi đến API có đến từ người dùng hoặc hệ thống được cấp quyền hay không. Khi bạn truy cập hệ thống NocoBase thông qua website, ứng dụng di động hoặc các script backend, “chìa khóa bí mật” này sẽ giúp hệ thống nhanh chóng xác minh danh tính của bạn.
Trong phần header của một HTTP request, API Key thường được truyền theo định dạng:
Authorization: Bearer {API key}Trong đó:
Bearer cho biết rằng chuỗi phía sau là một API Key hợp lệ
API Key cho phép hệ thống xác nhận nhanh quyền truy cập của người gửi yêu cầu
📌 API Keys thường được sử dụng trong các trường hợp sau:
🔹 Truy cập từ ứng dụng phía client
Khi người dùng gọi API từ trình duyệt web hoặc ứng dụng di động, hệ thống sẽ sử dụng API Key để xác thực danh tính, đảm bảo chỉ những người dùng được phép mới có thể truy xuất dữ liệu.
🔹 Thực thi các tác vụ tự động
Các tác vụ chạy nền như cron job, script định kỳ hoặc tiến trình tự động sử dụng API Key để đảm bảo rằng việc cập nhật dữ liệu hoặc ghi log được thực hiện một cách an toàn và có kiểm soát.
🔹 Phát triển và kiểm thử hệ thống
Trong quá trình phát triển, lập trình viên sử dụng API Key để mô phỏng các request thực tế, phục vụ cho việc debug, test API và kiểm tra tính ổn định của hệ thống.
2. Tạo API Keys trong NocoBase
2.1 Kích hoạt plugin Auth: API Keys
Trước tiên, hãy đảm bảo rằng plugin Auth: API Keys (xác thực bằng API Key) được tích hợp sẵn trong NocoBase đã được kích hoạt.
Sau khi kích hoạt, trong trung tâm cài đặt hệ thống sẽ xuất hiện một trang cấu hình mới dành riêng cho API Keys, cho phép bạn quản lý và sử dụng API Key trong ứng dụng.
2.2 Tạo Collection To Dos để kiểm thử
Để phục vụ cho việc kiểm thử, hãy tạo một collection có tên là todos (To Dos collection) với các trường sau:
id
title
completed
Sau đó, hãy thêm một vài công việc mẫu vào collection, ví dụ như:
ăn uống
ngủ
chơi game
2.3 Tạo và gán Role
Do API Key được gắn với Role, nên quyền truy cập của mỗi request sẽ phụ thuộc vào role tương ứng.
Vì vậy, trước khi tạo API Key, bạn cần tạo một role và phân quyền phù hợp.
Khuyến nghị bạn tạo một role thử nghiệm có tên “To Dos API Role”, sau đó cấp toàn bộ quyền truy cập cho collection To Dos đối với role này.
Nếu khi tạo API Key mà không thấy role “To Dos API Role” trong danh sách, rất có thể là do người dùng hiện tại chưa được gán role này.
👉 Trong trường hợp đó, hãy gán role “To Dos API Role” cho user đang đăng nhập, sau đó quay lại bước tạo API Key và thử lại.
Sau khi gán role, hãy tải lại trang và truy cập vào trang quản lý API Key. Nhấn “Add API Key”, lúc này bạn sẽ thấy role “To Dos API Role” xuất hiện trong danh sách.
Để quản lý chi tiết và rõ ràng hơn, bạn cũng có thể tạo một người dùng riêng mang tên “To Dos API User” để đăng nhập vào hệ thống, kiểm tra phân quyền và quản lý API Keys.
Chỉ cần gán role “To Dos API Role” cho người dùng này là có thể sử dụng đầy đủ các quyền liên quan.
2.4 Tạo và lưu API Key
Sau khi nhấn Submit, hệ thống sẽ hiển thị thông báo cho biết API Key đã được tạo thành công, đồng thời API Key sẽ xuất hiện trong một cửa sổ popup.
👉 Hãy sao chép và lưu lại API Key này ngay, vì với lý do bảo mật, hệ thống sẽ không hiển thị lại API Key này lần thứ hai.
Ví dụ, bạn có thể nhận được một API Key như sau:
2.5 Lưu ý
Thời hạn hiệu lực của API Key phụ thuộc vào khoảng thời gian bạn chọn khi tạo key.
Việc tạo và xác thực API Key phụ thuộc chặt chẽ vào biến môi trường APP_KEY. Không được thay đổi giá trị này một cách tùy ý, nếu không toàn bộ API Key trong hệ thống sẽ bị vô hiệu hóa.
3. Kiểm tra tính hợp lệ của API Key
3.1 Sử dụng plugin API Document
Mở plugin API Document, tại đây bạn có thể xem đầy đủ thông tin của từng API như:
phương thức request, URL, tham số và header.
3.2 Hiểu về các API CRUD cơ bản
Dưới đây là một số ví dụ API CRUD cơ bản được NocoBase cung cấp:
Truy vấn danh sách (List API):
GET {baseURL}/{collectionName}:list
Request Header:
- Authorization: Bearer <API key>
...(about 42 lines omitted)...Tạo bản ghi mới (API tạo dữ liệu):
POST {baseURL}/{collectionName}:create
Request Header:
- Authorization: Bearer <API key>
Request Body (in JSON format), for example:
{
"title": "123"
}Cập nhật bản ghi(update API):
POST {baseURL}/{collectionName}:update?filterByTk={id}
Request Header:
- Authorization: Bearer <API key>
Request Body (in JSON format), for example:
{
"title": "123",
"completed": true
}Xóa bản ghi(delete API):
POST {baseURL}/{collectionName}:destroy?filterByTk={id} Request Header: - Authorization: Bearer <API key>
Trong đó, {baseURL} là địa chỉ hệ thống NocoBase của bạn và {collectionName} là tên collection.
Ví dụ, khi test local với địa chỉ localhost:13000 và collection là todos, thì URL request sẽ là:
http://localhost:13000/todos:list3.3 Kiểm tra API Key bằng Postman (ví dụ với API lấy danh sách)
Mở Postman, tạo một yêu cầu GET mới, nhập URL request như ở trên, sau đó thêm header Authorization với giá trị là API Key của bạn.
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInJvbGVOYW1lIjoidG9kb3MiLCJpYXQiOjE3NDA5OTY1ODAsImV4cCI6MzMyOTg1OTY1ODB9.tXF2FCAzFNgZFPXqSBbWAfEvWkQwz0-mtKnmOTZT-5MSau khi gửi yêu cầu, nếu mọi thứ được thiết lập đúng, bạn sẽ nhận được phản hồi tương tự như sau:
{
"data": [
{
"createdAt": "2025-03-03T09:57:36.728Z",
"updatedAt": "2025-03-03T09:57:36.728Z",
"completed": null,
"createdById": 1,
"id": 1,
"title": "eat food",
"updatedById": 1
}
],
"meta": {
"count": 1,
"page": 1,
"pageSize": 20,
"totalPage": 1
}
}Nếu API key không được cấp quyền đúng, bạn có thể sẽ thấy thông báo lỗi như sau:
{
"errors": [
{
"message": "Your session has expired. Please sign in again.",
"code": "INVALID_TOKEN"
}
]
}Trong trường hợp này, hãy kiểm tra lại quyền của role, việc liên kết API key, đồng thời đảm bảo định dạng của API key là chính xác.
3.4 Sao chép mã request từ Postman
Khi việc kiểm thử thành công, bạn có thể sao chép mã request của List API. Ví dụ, đoạn lệnh curl dưới đây được sao chép trực tiếp từ Postman:
curl --location 'http://localhost:13000/api/todos:list' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInJvbGVOYW1lIjoidG9kb3MiLCJpYXQiOjE3NDA5OTY1ODAsImV4cCI6MzMyOTg1OTY1ODB9.tXF2FCAzFNgZFPXqSBbWAfEvWkQwz0-mtKnmOTZT-5M'4. Hiển thị danh sách To Dos trong Iframe Block
Để minh họa trực quan kết quả của các API request, chúng ta có thể sử dụng Iframe Block để hiển thị danh sách To Dos được lấy từ NocoBase. Tham khảo đoạn mã ví dụ bên dưới:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo List</title>
</head>
<body>
<h1>Todo List</h1>
<pre id="result"></pre>
<script>
fetch('http://localhost:13000/api/todos:list', {
method: 'GET',
headers: {
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInJvbGVOYW1lIjoidG9kb3MiLCJpYXQiOjE3NDA5OTY1ODAsImV4cCI6MzMyOTg1OTY1ODB9.tXF2FCAzFNgZFPXqSBbWAfEvWkQwz0-mtKnmOTZT-5M'
}
})
.then(response => response.json())
.then(data => {
document.getElementById('result').textContent = JSON.stringify(data, null, 2);
})
.catch(error => {
console.error('Error:', error);
});
</script>
</body>
</html>Đoạn mã trên nhúng một Iframe Block để hiển thị danh sách “Todo List” đơn giản. Khi iframe được tải, nó sẽ gọi API để lấy dữ liệu To Dos từ NocoBase và hiển thị kết quả trả về (dưới dạng JSON đã được định dạng) ngay bên trong iframe.
Ngoài ra, phần animation bên dưới minh họa quy trình gọi API và nhận dữ liệu một cách trực quan, động, giúp bạn dễ dàng hình dung cách hệ thống hoạt động khi có request được gửi đi.
5. Kết luận
Thông qua các bước trên, chúng ta đã tìm hiểu chi tiết cách tạo và sử dụng API Key trong NocoBase. Từ việc kích hoạt plugin, tạo collection, gán role, đến kiểm thử API và hiển thị dữ liệu bằng Iframe Block — mỗi bước đều đóng vai trò quan trọng. Cuối cùng, với sự hỗ trợ của DeepSeek, một trang To Do đơn giản đã được tạo ra. Bạn hoàn toàn có thể chỉnh sửa và mở rộng thêm đoạn mã theo nhu cầu của mình.
Đoạn code cho ví dụ này:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Minimalist To-Do</title>
<script src="https://unpkg.com/vue@3"></script>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-50 min-h-screen">
<div id="app" class="max-w-lg mx-auto p-6 mt-8">
<!-- Add new input field -->
<div class="flex gap-3 mb-8">
<input
v-model="newTodo"
@keyup.enter="addTodo"
class="flex-1 p-3 border-2 border-gray-200 rounded-xl shadow focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none placeholder-gray-400"
placeholder="Enter a to-do item..."
>
<button
@click="addTodo"
class="px-5 py-3 bg-blue-500 text-white rounded-xl hover:bg-blue-600 transition shadow-md hover:shadow-lg"
>Add</button>
</div>
<!-- To-do list -->
<div class="space-y-3">
<div
v-for="todo in todos"
:key="todo.id"
class="group flex items-center p-4 bg-white rounded-xl shadow-md hover:shadow-lg transition duration-200"
>
<!-- Completion status -->
<input
type="checkbox"
v-model="todo.completed"
@change="toggleTodo(todo)"
class="w-5 h-5 mr-3 text-blue-500 rounded-lg border-2 border-gray-300 checked:bg-blue-500 checked:border-blue-500 focus:ring-blue-500"
>
<!-- Editable text -->
<div
@click="startEdit(todo)"
class="flex-1"
>
<input
v-if="todo.editing"
v-model="todo.title"
@blur="saveEdit(todo)"
@keyup.enter="saveEdit(todo)"
class="w-full p-1 border-b-2 focus:outline-none focus:border-blue-500 font-medium"
>
<span
v-else
:class="{ 'line-through text-gray-400': todo.completed }"
class="cursor-text text-gray-700 font-medium"
>{{ todo.title }}</span>
</div>
<!-- Delete button -->
<button
@click="deleteTodo(todo.id)"
class="ml-2 text-gray-400 hover:text-red-500 transition duration-150 opacity-0 group-hover:opacity-100 text-xl font-bold"
>×</button>
</div>
</div>
</div>
<script>
const { createApp } = Vue
createApp({
data() {
return {
todos: [],
newTodo: '',
API: 'http://localhost:13000/api/todos',
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInJvbGVOYW1lIjoidG9kb3MiLCJpYXQiOjE3NDA5OTY1ODAsImV4cCI6MzMyOTg1OTY1ODB9.tXF2FCAzFNgZFPXqSBbWAfEvWkQwz0-mtKnmOTZT-5M' // Replace with actual token
}
},
mounted() {
this.loadTodos()
},
methods: {
async loadTodos() {
const res = await fetch(`${this.API}:list`, {
headers: { Authorization: `Bearer ${this.token}` }
})
this.todos = (await res.json()).data.map(t => ({...t, editing: false}))
},
async addTodo() {
if (!this.newTodo) return
await fetch(`${this.API}:create`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ title: this.newTodo })
})
this.newTodo = ''
this.loadTodos()
},
async toggleTodo(todo) {
await fetch(`${this.API}:update?filterByTk=${todo.id}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ completed: todo.completed })
})
},
async deleteTodo(id) {
await fetch(`${this.API}:destroy?filterByTk=${id}`, {
method: 'POST',
headers: { Authorization: `Bearer ${this.token}` }
})
this.loadTodos()
},
startEdit(todo) {
todo.editing = true
},
async saveEdit(todo) {
todo.editing = false
await fetch(`${this.API}:update?filterByTk=${todo.id}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ title: todo.title })
})
}
}
}).mount('#app')
</script>
</body>
</html>





















