Hôm nay ngồi cafe, lướt qua một dự án cũ của mình thì thấy đau cả đầu vì cái cách thiết kế API hồi đó. Lúc ấy mình mê mẩn concept RESTful đến mức cực đoan, cứ nghĩ chỉ cần dùng HTTP method đúng là đủ. Nhưng càng làm lớn thì càng thấy những hạn chế của nó, đặc biệt là vấn đề over-fetching và under-fetching.
Tưởng tượng xem, bạn cần hiển thị danh sách bài viết, mỗi bài chỉ cần tiêu đề và ngày đăng. Nhưng API REST của mình lại trả về toàn bộ object: nội dung dài dằng dặc, danh sách comment, profile tác giả kèm avatar, thống kê lượt thích... Client chỉ cần 30 bytes mà server ship cả 2MB. Khổ lắm, tốn bandwidth, tốn thời gian render, user chờ loading mặt đen sì.
Cái hồi mình chuyển sang dùng GraphQL thì đúng là thấy "sướng" hẳn. Client hỏi gì server trả nấy, không thừa không thiếu. Nhưng cũng có cái giá phải trả là độ phức tạp khi setup schema và query depth. Đặc biệt là phần bảo mật, mình phải đau đầu thiết kế Rate Limiting và N+1 query cực kỹ.
Còn nhắc đến OAuth thì lại là một chuyện khác. Hồi mới làm, mình tự roll-out cái auth flow bằng JWT đơn giản, nghĩ là xong. Ai dè, bị hacker dò lỗ hổng, token bị đánh cắp, session bị giả mạo. Cuối cùng phải về nguồn, dùng thư viện chuẩn, tích hợp OAuth2 với provider như Google hay Facebook thì mới an tâm. Lesson học được là: Don't reinvent the wheel.
Cuối cùng là WebSocket. Lúc làm tính năng chat realtime, mình thấy HTTP request/response truyền thống quá chập chờn. Phải dùng long-polling thì pin tẹt ngất. Switch sang WebSocket, kết nối duy trì liên tục, data trôi tuột vào client như nước chảy. Nhưng cái khó là xử lý reconnection và quản lý state trên server khi có hàng ngàn socket mở cùng lúc.
Tóm lại, không có công nghệ nào là "thần thánh" cả. REST vẫn tốt cho cache và đơn giản. GraphQL mạnh ở tính linh hoạt. WebSocket là vua của realtime. OAuth là tiêu chuẩn vàng cho auth. Việc của chúng ta là chọn đúng công cụ cho đúng bài toán, chứ đừng cố nhét tất cả vào một cái rổ.
Có lần mình debug lỗi một request bị từ chối, code thì đơn giản thế này:
fetch('https://api.example.com/data', { method: 'GET', headers: { 'Authorization': 'Bearer ' + token } })
Mà vẫn bị 401 Unauthorized. Hóa ra là token đã hết hạn mà mình quên refresh! Một bài học nhỏ về việc quản lý lifecycle của token trong OAuth. Nghề dev thú vị vì luôn có những "bẫy" nhỏ như vậy để rèn luyện sự cẩn thận mà.