Tổng hợp 37 câu hỏi phỏng vấn Backend & API kèm đáp án chi tiết, song ngữ Việt–Anh — sắp xếp từ cơ bản đến nâng cao. Ôn luyện miễn phí, tự động lưu tiến độ.
Rate limiting giới hạn số request một client được gửi trong khoảng thời gian → chống lạm dụng/DoS, đảm bảo công bằng, kiểm soát chi phí. Vượt hạn trả 429 Too Many Requests (thường kèm header Retry-After). Thuật toán phổ biến: - Fixed window: đếm…
Vấn đề: POST không idempotent — nếu client gửi tạo đơn/thanh toán rồi mạng timeout, nó không biết server đã nhận chưa. Retry khi chưa biết kết quả → tạo trùng (đơn hàng lặp, trừ tiền hai lần). Idempotency key là một chuỗi duy nhất…
- Offset (LIMIT 20 OFFSET 40 / ?page=3): đơn giản, nhảy trang bất kỳ, hiện tổng số trang. Hai điểm yếu: (1) chậm ở trang sâu — DB vẫn quét rồi bỏ 40 hàng đầu; (2) lệch kết quả — nếu có bản ghi được…
Safe = method chỉ đọc, không làm thay đổi trạng thái phía server (GET, HEAD, OPTIONS). Idempotent = gọi 1 lần hay N lần cho cùng kết quả trạng thái (GET, HEAD, PUT, DELETE, OPTIONS). Mọi method safe đều idempotent, ngược lại thì không. Method…
PUT thay thế toàn bộ resource bằng body gửi lên: field nào không có trong body được coi như bị xoá/đưa về mặc định. PATCH chỉ mô tả phần thay đổi. Hai định dạng PATCH phổ biến: - JSON Merge Patch (application/merge-patch+json): body trông giống…
Chọn theo việc đã làm xong chưa và có body trả về không: - 201 Created — đã tạo xong resource mới. Kèm header Location trỏ tới URL của resource vừa tạo, body thường là chính resource đó. - 200 OK — xử lý xong…
Ba mã ứng với ba tầng lỗi khác nhau: - 400 Bad Request — request sai cú pháp, server không parse nổi: JSON hỏng, thiếu field bắt buộc, kiểu dữ liệu sai (age: "abc"), query param không hợp lệ. - 422 Unprocessable Content — cú…
Nguyên tắc: một định dạng lỗi duy nhất cho toàn API, máy đọc được và người debug được. RFC 9457 chuẩn hoá đúng việc đó với Content-Type: application/problem+json. Các field chuẩn: - type — URI định danh loại lỗi (client so khớp field này, không…
Dùng idempotency key do client sinh, server ghi nhớ kết quả và phát lại thay vì xử lý lại. Luồng: 1. Client sinh key duy nhất cho mỗi ý định thanh toán (UUID v4, sinh lúc mở màn hình checkout, giữ nguyên khi retry) và…
Hai cách phổ biến: - URL path (/v1/orders) — Google API design guide và phần lớn API công khai chọn cách này. Dễ nhìn, dễ route, dễ cache, dễ chia traffic ở gateway. Nhược điểm: cùng một resource có nhiều URI. - Header (Accept: application/vnd.api+json;…
Thuật toán, từ đơn giản đến chính xác: - Fixed window — đếm request theo từng phút. Đơn giản nhất nhưng có lỗi biên: 100 request cuối phút 1 và 100 request đầu phút 2 → 200 request trong 2 giây vẫn hợp lệ. -…
Giữ một quy ước duy nhất cho mọi collection endpoint, đừng mỗi endpoint một kiểu. - Filter: field đơn giản thì đặt thẳng làm query param (status=paid). Cần biểu thức phức tạp thì dùng một param filter với cú pháp cố định (filter=status=paid AND total100000)…
Chuyển từ request đồng bộ sang async job: nhận yêu cầu, trả ngay, xử lý nền, client theo dõi kết quả. Sau đó client theo dõi bằng một trong hai cách: Polling — GET /jobs/7c2 trả { "status": "running" "succeeded" "failed", "progress": 0.4 }. Khi…
Trước hết phải chốt ngữ nghĩa với bên gọi, vì đây là câu hỏi nghiệp vụ chứ không phải câu hỏi HTTP: Cách 1 — all-or-nothing (atomic). Cả batch chạy trong một transaction, một bản ghi lỗi thì rollback toàn bộ, trả 422 kèm danh…
Vì DB và message broker là hai hệ thống riêng biệt, không nằm chung một transaction. Bạn ghi vào cả hai trong cùng một hàm, nhưng không có gì đảm bảo cả hai cùng thành công. Hai chiều hỏng: - Ghi DB xong, publish lỗi…
Idempotent nghĩa là xử lý cùng một message nhiều lần cho kết quả giống hệt xử lý một lần. Cần thiết vì broker giao at-least-once: retry, rebalance, ack rớt đều sinh bản lặp. Cách làm phổ biến — lưu dấu vết message đã xử lý…
Retry ngay lập tức và không giới hạn là cách nhanh nhất để biến một sự cố nhỏ thành sự cố lớn: service phía sau đang quá tải lại nhận thêm lưu lượng retry. Exponential backoff — giãn khoảng chờ theo cấp số nhân (1s,…
Đầu tiên phải phân biệt hai tình huống, vì cách xử lý khác hẳn nhau. Chậm tạm thời (đợt cao điểm) — queue chính là bộ đệm, đó là công dụng của nó. Chỉ cần đủ dung lượng lưu trữ và giám sát để biết…
Chọn theo cách dữ liệu được tiêu thụ, không theo độ phổ biến. Kafka — log phân tán, message được giữ lại theo retention và consumer đọc bằng offset. Chọn khi: - Cần replay: thêm service mới muốn đọc lại lịch sử, hoặc phải chạy…
Không bao giờ dùng float/double cho tiền. Số thực nhị phân không biểu diễn chính xác 0.1, cộng dồn nhiều dòng sẽ lệch xu và lệch đối soát. Hai cách đúng: - Số nguyên theo đơn vị nhỏ nhất: lưu amountminor BIGINT. VND không có…
Mô hình tối thiểu là ba bảng: users, roles, permissions, cộng hai bảng nối userroles và rolepermissions. User nhận role, role gom permission dạng động từ + tài nguyên (order.read, order.refund, user.ban). Quy tắc khi cài đặt: - Kiểm tra ở server, mọi request. Ẩn…
Khi request mang cookie cross-origin, trình duyệt siết quy tắc chặt hơn bình thường. Server phải trả đủ hai header: - Access-Control-Allow-Origin: https://app.example.com — phải là origin cụ thể, dùng sẽ bị chặn. - Access-Control-Allow-Credentials: true. Nếu là preflight, response OPTIONS cũng phải lặp lại…
Câu hỏi đầu tiên không phải chọn giao thức mà là: người gọi có cần kết quả ngay mới đi tiếp được không? Đồng bộ (REST / gRPC) — cần kết quả để xử lý tiếp: kiểm tra tồn kho trước khi tạo đơn, xác…
Gateway là cửa ngõ duy nhất cho client vào hệ thống, xử lý các cross-cutting concern — thứ mọi service đều cần và không nên viết lại 10 lần. Nên làm: - Định tuyến request tới service phù hợp; ẩn cấu trúc nội bộ khỏi…
BFF là một backend riêng cho từng loại client (web, iOS/Android, màn hình nội bộ), do chính đội frontend đó sở hữu, đứng giữa client và các service nghiệp vụ. Vấn đề nó giải quyết: một API dùng chung cho mọi client thì luôn có…
Nguyên tắc: thay đổi tương thích ngược thì không cần version mới; breaking change thì phải chạy song song hai phiên bản một thời gian. Thay đổi an toàn (thêm, không bỏ): thêm trường mới, thêm giá trị enum có xử lý mặc định, thêm…
Có. ORM chỉ an toàn ở phần nó tự sinh câu lệnh; mọi chỗ bạn tự ghép chuỗi đều quay lại rủi ro cũ. Ba chỗ hở hay gặp: 1. Raw query nối chuỗi. Escape hatch của ORM ($queryRawUnsafe, createQuery với chuỗi, query() của driver)…
Rủi ro là command injection: khi chuỗi được đưa qua shell, các ký tự ;, , &&, $(...), backtick được shell diễn giải thành lệnh mới, chạy dưới quyền của process ứng dụng. Cách viết lại — bỏ shell đi: execFile/spawn (với shell: false, là…
Cần, và đây là bắt buộc tuyệt đối. Validate ở client là trải nghiệm người dùng, không phải kiểm soát bảo mật — client nằm hoàn toàn trong tay người dùng, ai cũng gọi thẳng API bằng curl hay Postman được, bỏ qua toàn bộ…
Đây là excessive data exposure: API trả tất cả những gì có rồi để client tự chọn hiển thị. Nhưng client không phải nơi giấu dữ liệu — mở tab Network là thấy toàn bộ response. Trả thẳng entity ORM thường kéo theo passwordhash, resettoken,…