Flutter, một UI toolkit đến từ Google, cho phép xây dựng ứng dụng mobile, web và desktop đẹp và native từ một codebase duy nhất. Node.js là một runtime environment cho JavaScript ở phía server, rất phổ biến để xây dựng các API nhanh và có khả năng mở rộng. Việc kết hợp sức mạnh của Flutter ở frontend và Node.js ở backend tạo nên một stack phát triển hiện đại và hiệu quả.
Bài viết này sẽ đi sâu vào cách ứng dụng Flutter của bạn có thể giao tiếp với API được xây dựng bằng Node.js, tập trung vào việc thực hiện các yêu cầu HTTP và xử lý dữ liệu.

1. Thiết lập môi trường
Trước khi bắt đầu code, chúng ta cần đảm bảo môi trường phát triển đã sẵn sàng.
1.1 Chuẩn bị API Node.js
Để làm theo hướng dẫn này, bạn cần có một API Node.js đang chạy và có thể truy cập được. Nếu bạn chưa có, bạn có thể tạo một API cơ bản rất nhanh với Express.js. Dưới đây là ví dụ về một API Node.js đơn giản trả về danh sách người dùng và cho phép thêm người dùng mới:
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
const port = 3000;
app.use(cors());
app.use(bodyParser.json());
let users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
app.get('/api/users', (req, res) => {
res.json(users);
});
app.post('/api/users', (req, res) => {
const newUser = req.body;
if (!newUser || !newUser.name) {
return res.status(400).json({ message: 'Name is required' });
}
newUser.id = users.length + 1;
users.push(newUser);
res.status(201).json(newUser);
});
app.listen(port, () => {
console.log(`Node.js API listening at http://localhost:${port}`);
});
Lưu đoạn code trên vào một file (ví dụ: server.js
), cài đặt các dependencies (npm install express body-parser cors
) và chạy nó (node server.js
). Đảm bảo API chạy trên một địa chỉ và cổng mà thiết bị Flutter của bạn có thể truy cập (ví dụ: http://10.0.2.2:3000
nếu chạy trên Android emulator và server trên localhost
).
1.2 Thiết lập Project Flutter
Nếu bạn đã có project Flutter, hãy mở file pubspec.yaml
. Nếu chưa, tạo project mới bằng flutter create your_app_name
.
Chúng ta sẽ sử dụng package http
để đơn giản. Thêm http
vào phần dependencies
trong pubspec.yaml
:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
http: ^0.13.3
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
flutter:
uses-material-design: true
Sau khi thêm, chạy lệnh flutter pub get
trong terminal của project Flutter để cài đặt package.
2. Thực hiện HTTP Request từ Flutter
Package http
cung cấp các phương thức dễ sử dụng để thực hiện các yêu cầu HTTP phổ biến như GET, POST, PUT, DELETE.
Trước tiên, import package http
và dart:convert
(để xử lý JSON) vào file Dart của bạn:
import 'package:http/http.dart' as http;
import 'dart:convert';

2.1 GET Request: Lấy dữ liệu
Để lấy danh sách người dùng từ API Node.js ví dụ ở trên, bạn có thể tạo một hàm bất đồng bộ sử dụng http.get()
:
Future<List<dynamic>> fetchUsers() async {
final response = await http.get(Uri.parse('YOUR_NODEJS_API_URL/api/users'));
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception('Failed to load users');
}
}
Bạn cần thay thế 'YOUR_NODEJS_API_URL'
bằng địa chỉ IP và cổng thực tế của API Node.js server của bạn.
2.2 POST Request: Gửi dữ liệu
Để thêm một người dùng mới, bạn sử dụng phương thức http.post()
. Bạn cần cung cấp URL, headers (để thông báo định dạng dữ liệu gửi đi là JSON) và body (dữ liệu cần gửi, đã được encode sang chuỗi JSON).
Future<void> createUser(String name) async {
final response = await http.post(
Uri.parse('YOUR_NODEJS_API_URL/api/users'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{'name': name}),
);
if (response.statusCode == 201) {
print('User created successfully: ${response.body}');
} else {
throw Exception('Failed to create user: ${response.statusCode}');
}
}

3. Xử lý bất đồng bộ với Async/Await
Các thao tác mạng trong Flutter (và Dart) là bất đồng bộ. Điều này có nghĩa là chúng không chặn luồng chính của ứng dụng, giúp UI luôn mượt mà. Từ khóa async
và await
là cách hiện đại và dễ đọc để làm việc với các thao tác bất đồng bộ.
async
: Được đặt trước một hàm để báo hiệu rằng hàm đó sẽ thực hiện các thao tác bất đồng bộ.
await
: Được sử dụng bên trong một hàm async
để chờ kết quả của một Future mà không chặn toàn bộ luồng thực thi. Khi gặp await
, hàm sẽ tạm dừng, giải phóng CPU để làm việc khác, và sẽ tiếp tục chạy khi Future hoàn thành.
Các ví dụ fetchUsers
và createUser
ở trên đều sử dụng async/await
để chờ kết quả từ http.get
và http.post
.
4. Xử lý lỗi và phản hồi cho người dùng
Việc xử lý lỗi API là rất quan trọng để ứng dụng của bạn ổn định và cung cấp phản hồi rõ ràng cho người dùng. Luôn bọc các lệnh gọi API trong khối try-catch
.
void _loadUsers() async {
try {
List<dynamic> usersList = await fetchUsers();
print('Fetched ${usersList.length} users.');
} catch (e) {
print('Error fetching users: $e');
}
}
void _addUser(String name) async {
try {
await createUser(name);
print('User added successfully.');
} catch (e) {
print('Error adding user: $e');
}
}
Khi server trả về mã trạng thái lỗi (ví dụ: 400, 404, 500), phương thức http.get
hoặc http.post
sẽ không tự động throw lỗi. Bạn cần kiểm tra thuộc tính statusCode
của response và throw exception một cách thủ công nếu cần xử lý trong khối catch
.
5. Best Practices
- Sử dụng biến môi trường: Không nên hardcode URL API trong code. Sử dụng các package như
flutter_dotenv
để quản lý biến môi trường.
- Mô hình hóa dữ liệu: Thay vì làm việc trực tiếp với
dynamic
hoặc Map<String, dynamic>
, hãy tạo các Dart class để mô hình hóa dữ liệu nhận được từ API (sử dụng json_serializable
giúp tự động hóa).
- Xử lý lỗi chi tiết: Phân loại các loại lỗi (lỗi mạng, lỗi server, lỗi parsing) và cung cấp thông báo cụ thể cho người dùng.
- Sử dụng Dio thay vì http (Tùy chọn): Đối với các ứng dụng lớn hơn, package
dio
thường được ưa chuộng hơn http
vì nó cung cấp nhiều tính năng hơn như interceptors, global configuration, form data, request cancellation, v.v.
- Bảo mật: Đảm bảo kết nối API của bạn an toàn (sử dụng HTTPS). Xử lý xác thực và ủy quyền đúng cách.
Kết luận
Kết nối ứng dụng Flutter với API Node.js là một tác vụ phổ biến khi xây dựng các ứng dụng full-stack. Bằng cách hiểu rõ cách thực hiện HTTP requests, xử lý bất đồng bộ và quản lý lỗi trong Flutter, bạn có thể dễ dàng tích hợp ứng dụng mobile của mình với backend Node.js mạnh mẽ, mở ra nhiều khả năng phát triển ứng dụng.
Tài Liệu Tham Khảo