Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Chained Requests — Workflow đa bước

Mở đầu — vì sao bài này quan trọng

Trong thực tế kiểm thử API, hiếm khi một nghiệp vụ chỉ gói gọn trong đúng một request. Hãy nghĩ về một luồng đặt hàng trên một sàn thương mại điện tử như Tiki hay Shopee: đầu tiên bạn phải đăng nhập để lấy token, sau đó tạo giỏ hàng, thêm sản phẩm vào giỏ, tạo đơn hàng từ giỏ đó, rồi cuối cùng gọi cổng thanh toán. Mỗi bước đều phụ thuộc vào kết quả của bước trước — bạn không thể tạo đơn hàng nếu không có cart_id mà bước trước trả về, và không thể thanh toán nếu không có order_id.

Đây chính là bản chất của Chained Requests (request nối chuỗi): một workflow nghiệp vụ được kiểm thử bằng nhiều request liên tiếp, trong đó dữ liệu chảy từ response của request này sang request tiếp theo. Nếu bạn chỉ biết gửi từng request rời rạc và copy-paste thủ công order_id từ tab này sang tab khác, bạn sẽ không bao giờ tự động hóa được kiểm thử end-to-end, và cũng không thể chạy nó trong CI/CD.

Bài học này tập trung vào đúng hai công cụ cốt lõi mà Postman cung cấp để dựng chuỗi: truyền dữ liệu giữa các request (thông qua pm.collectionVariables và các scope biến khác) và điều khiển thứ tự thực thi (thông qua pm.execution.setNextRequest). Nắm được hai thứ này, bạn có thể mô phỏng bất kỳ luồng nghiệp vụ nhiều bước nào một cách hoàn toàn tự động.

Khái niệm cốt lõi

Chained request là gì

Một chuỗi request là một dãy các lời gọi API được sắp xếp theo trình tự, trong đó ít nhất một request cần dữ liệu do request trước sinh ra. Cơ chế hoạt động gồm hai phần tách biệt nhưng phối hợp với nhau:

  • Trích xuất và lưu dữ liệu: Ở tab Tests (script chạy sau khi có response) của request A, ta đọc giá trị từ response body và lưu vào một biến để request B dùng lại.
  • Điều khiển luồng: Bằng cách gọi setNextRequest, ta chỉ định request nào sẽ chạy tiếp theo, thay vì để Postman chạy tuần tự theo thứ tự trong collection.

Lưu trữ dữ liệu trung gian: chọn đúng scope

Postman có nhiều loại biến với phạm vi (scope) khác nhau. Để nối chuỗi, thứ bạn cần là một scope tồn tại xuyên suốt một lần chạy collection nhưng không dính vào cấu hình môi trường. Đó chính là collectionVariables.

// Trong tab Tests của request "Login"
const res = pm.response.json();
pm.collectionVariables.set("authToken", res.data.access_token);
pm.collectionVariables.set("userId", res.data.user.id);

Ở request tiếp theo, bạn dùng lại bằng cú pháp {{authToken}} trong URL/header/body, hoặc đọc trong script bằng pm.collectionVariables.get("authToken").

Vì sao ưu tiên collectionVariables cho việc nối chuỗi thay vì environmentVariables? Vì dữ liệu trung gian như order_id, cart_idtạm thời, chỉ có ý nghĩa trong đúng lần chạy hiện tại. Nếu bạn nhét chúng vào environment (nơi vốn để chứa cấu hình bền như base_url, api_key), bạn sẽ làm bẩn file environment và gây rối khi nhiều người cùng chạy. collectionVariables bị reset gọn gàng theo từng lần chạy, đúng bản chất "dữ liệu bay hơi".

Điều khiển thứ tự với setNextRequest

Mặc định, khi bạn nhấn Run collection, Postman chạy các request từ trên xuống dưới theo đúng thứ tự trong thư mục. Nhưng đôi khi bạn cần rẽ nhánh: "nếu đơn hàng tạo thất bại, bỏ qua bước thanh toán và nhảy tới bước dọn dẹp". Đó là lúc setNextRequest phát huy tác dụng.

// Cú pháp mới (Postman gần đây)
pm.execution.setNextRequest("Create Order");

// Cú pháp cũ, vẫn còn dùng rộng rãi postman.setNextRequest("Create Order");

// Dừng hẳn chuỗi tại đây pm.execution.setNextRequest(null);

Ba điều tối quan trọng cần nhớ về setNextRequest:

  • chỉ có hiệu lực khi chạy bằng Collection Runner hoặc Newman, không có tác dụng khi bạn bấm Send thủ công từng request.
  • Tham số là tên request (đúng chính tả, phân biệt hoa thường), không phải URL.
  • Dù bạn đặt lệnh này ở đầu hay giữa script, Postman vẫn chạy hết script hiện tại rồi mới nhảy — nó chỉ thay đổi request kế tiếp, không cắt ngang request hiện tại.

Tình huống thực tế

Ví dụ 1: Luồng đặt hàng của một sàn TMĐT nội địa

Giả sử bạn là QA tại một công ty thương mại điện tử ở TP.HCM, tạm gọi là "ChoNhanh". Bạn cần kiểm thử luồng mua hàng hoàn chỉnh gồm 5 bước: Login → Create Cart → Add Item → Create Order → Pay.

Ở request Login, tab Tests lưu token và user id:

const res = pm.response.json();
pm.test("Login thành công", () => pm.response.to.have.status(200));
pm.collectionVariables.set("authToken", res.access_token);

Create Cart, header dùng Authorization: Bearer {{authToken}}, và tab Tests lưu cartId:

pm.collectionVariables.set("cartId", pm.response.json().cart_id);

Create Order, body gửi lên {"cart_id": "{{cartId}}"} và lưu orderId. Cuối cùng Pay dùng {{orderId}}.

Bài học rút ra: Toàn bộ chuỗi này chạy được trên máy CI mà không cần một thao tác tay nào. Trước khi áp dụng, đội của ChoNhanh mất khoảng 15 phút mỗi lần chạy tay để kiểm luồng đặt hàng trước khi release; sau khi dựng chuỗi, một lệnh newman run chạy xong trong 20 giây. Điểm mấu chốt là dữ liệu tự chảy — không ai còn phải copy order_id bằng tay.

Ví dụ 2: Rẽ nhánh theo trạng thái tồn kho

Vẫn tại ChoNhanh, nhóm QA gặp một yêu cầu khó hơn: sản phẩm khuyến mãi có thể hết hàng bất kỳ lúc nào. Khi đó, request Add Item trả về HTTP 409 với body {"error": "out_of_stock"}. Nếu cứ máy móc chạy tiếp tới Create Order, cả chuỗi sẽ báo lỗi hàng loạt và làm nhiễu báo cáo.

Giải pháp là rẽ nhánh ngay trong tab Tests của Add Item:

if (pm.response.code === 409) {
    pm.collectionVariables.set("skipReason", "out_of_stock");
    pm.execution.setNextRequest("Cleanup Cart"); // bỏ qua Order & Pay
} else {
    pm.test("Thêm sản phẩm OK", () => pm.response.to.have.status(200));
    // không gọi setNextRequest -> chạy tiếp request kế theo thứ tự
}

Bài học rút ra: setNextRequest biến một chuỗi tuyến tính thành một máy trạng thái nhỏ. Thay vì để test thất bại giả (false negative) vì tình huống hợp lệ về mặt nghiệp vụ (hết hàng là chuyện bình thường), bạn điều hướng luồng sang nhánh dọn dẹp và giữ báo cáo sạch. Đây là khác biệt giữa một bộ test "chạy được" và một bộ test "đáng tin".

Ví dụ 3: Polling một tác vụ bất đồng bộ ở fintech

Một ví dụ Đông Nam Á khác: một startup fintech ở Singapore cung cấp API xác minh danh tính (eKYC). Khi bạn gọi Submit KYC, API trả về ngay request_id với trạng thái processing — kết quả thật chỉ có sau vài giây xử lý ở backend. Bạn cần lặp việc gọi Check Status cho đến khi trạng thái thành done.

setNextRequest cho phép tự trỏ vào chính request đang chạy để tạo vòng lặp polling:

// Trong tab Tests của "Check Status"
const status = pm.response.json().status;
let tries = pm.collectionVariables.get("kycTries") || 0;

if (status === "processing" && tries < 5) { pm.collectionVariables.set("kycTries", tries + 1); pm.execution.setNextRequest("Check Status"); // lặp lại chính nó } else { pm.test("KYC hoàn tất", () => pm.expect(status).to.eql("done")); pm.execution.setNextRequest(null); // dừng chuỗi }

Bài học rút ra: Chuỗi request không chỉ đi thẳng mà còn có thể lặp có điều kiện. Biến đếm kycTries đóng vai trò van an toàn để tránh vòng lặp vô tận nếu backend treo. (Lưu ý: nếu cần chờ giữa các lần lặp, bạn nên kết hợp với một cơ chế delay của Runner/Newman thay vì để chuỗi gọi liên tục dồn dập.)

Hướng dẫn từng bước

Hãy dựng một chuỗi 3 bước đơn giản Login → Get Profile → Update Profile để bạn tự tay làm theo:

  • Tạo collection và 3 request đặt tên rõ ràng: Login, Get Profile, Update Profile. Tên request chính là "địa chỉ" mà setNextRequest sẽ trỏ tới, nên đặt tên nhất quán ngay từ đầu.
  • Ở request Login, cấu hình phương thức POST với body chứa thông tin đăng nhập. Sang tab Tests viết:
   const res = pm.response.json();
   pm.test("Đăng nhập OK", () => pm.response.to.have.status(200));
   pm.collectionVariables.set("token", res.token);
   
  • Ở request Get Profile, thêm header Authorization: Bearer {{token}}. Trong tab Tests, lưu lại dữ liệu bạn muốn dùng cho bước sau:
   pm.collectionVariables.set("profileId", pm.response.json().id);
   
  • Ở request Update Profile, dùng {{profileId}} trong URL (ví dụ /users/{{profileId}}) và {{token}} trong header. Đây là nơi mọi dữ liệu trung gian hội tụ.
  • Chạy bằng Collection Runner: mở Runner, chọn collection, nhấn Run. Quan sát cột kết quả — nếu tokenprofileId được truyền đúng, cả ba bước sẽ xanh. Nếu bạn thấy {{profileId}} xuất hiện nguyên văn trong URL request cuối, nghĩa là biến chưa được set.
  • Thêm rẽ nhánh (tùy chọn): ở tab Tests của Login, thêm if (pm.response.code !== 200) pm.execution.setNextRequest(null); để dừng ngay nếu đăng nhập hỏng — không đời nào nên chạy tiếp khi chưa có token.
  • Kiểm tra biến sau khi chạy: mở phần Variables của collection (tab Variables ở cấp collection) để xác nhận giá trị token, profileId đã được ghi. Đây là cách debug nhanh nhất khi chuỗi trục trặc.

Lỗi thường gặp & mẹo

  • setNextRequest không có tác dụng khi bấm Send: Đây là lỗi số một của người mới. Cơ chế điều khiển luồng chỉ hoạt động trong Collection Runner hoặc Newman. Bấm Send từng request thì lệnh này bị bỏ qua hoàn toàn.
  • Sai tên request: setNextRequest("create order") sẽ không tìm thấy nếu request thật tên là Create Order. Tên phân biệt hoa thường và phải khớp tuyệt đối. Nếu có nhiều request trùng tên, Postman thường nhảy tới cái đầu tiên tìm thấy — nên đặt tên duy nhất.
  • Nhầm lẫn scope biến: Nếu bạn set vào pm.variables (biến cục bộ, chỉ sống trong một request) thay vì pm.collectionVariables, dữ liệu sẽ biến mất trước khi request sau đọc được. Với dữ liệu cần truyền qua nhiều request, luôn dùng collectionVariables (hoặc environment nếu thực sự cần bền).
  • Quên van an toàn khi polling: Vòng lặp setNextRequest trỏ về chính nó mà không có biến đếm hoặc điều kiện dừng sẽ chạy mãi mãi. Luôn có bộ đếm và ngưỡng tối đa.
  • Không dọn biến giữa các lần chạy: collectionVariables có thể còn sót giá trị của lần chạy trước. Mẹo hay là đặt một request "Setup" ở đầu chuỗi để pm.collectionVariables.unset(...) hoặc reset các biến đếm về 0.
  • Mẹo debug bằng console: rải console.log("orderId =", pm.collectionVariables.get("orderId")) trong script và mở Postman Console (View → Show Postman Console) để soi giá trị thực tế đang chảy qua chuỗi. Đây là công cụ chẩn đoán nhanh và đáng tin nhất.
  • Giữ chuỗi có thể chạy lặp lại (idempotent): nếu request tạo dữ liệu (tạo user, tạo đơn), hãy thêm bước dọn dẹp ở cuối, nếu không lần chạy sau có thể lỗi vì trùng dữ liệu.

Bài tập thực hành

  • Dựng chuỗi cơ bản: Tạo collection 3 request Login → Create Post → Delete Post với một API giả lập bất kỳ (ví dụ reqres.in hoặc jsonplaceholder). Truyền token và postId qua collectionVariables. Xác nhận cả chuỗi xanh khi chạy bằng Runner.
  • Thêm rẽ nhánh: Ở request Login, cố tình gửi sai mật khẩu. Viết script sao cho khi status khác 200 thì setNextRequest(null) để dừng chuỗi ngay, và collection không cố gắng tạo post với token rỗng.
  • Bài nâng cao — polling: Nếu bạn có quyền truy cập một API bất đồng bộ, hãy dựng vòng lặp Check Status tự trỏ vào chính nó, giới hạn tối đa 5 lần thử bằng một biến đếm, và dừng khi trạng thái đạt done. Nếu không có API sẵn, hãy mô phỏng bằng một Mock Server trả về processing rồi done.
  • Tự phản tư: Viết ra 2–3 câu trả lời cho câu hỏi: "Trong dự án hiện tại của tôi, nghiệp vụ nào cần tối thiểu 3 request nối tiếp, và dữ liệu nào phải chảy giữa chúng?" Đây là bước quan trọng nhất để biến kiến thức thành ứng dụng thật.

Tóm tắt

Chained Requests là kỹ thuật nền tảng để kiểm thử các luồng nghiệp vụ nhiều bước — từ đặt hàng trên sàn TMĐT đến xác minh eKYC ở fintech. Hai trụ cột của nó là: truyền dữ liệu giữa các request (ưu tiên pm.collectionVariables vì đúng bản chất dữ liệu tạm thời) và điều khiển luồng bằng pm.execution.setNextRequest (chỉ hoạt động trong Collection Runner/Newman, nhận tên request phân biệt hoa thường).

Với hai công cụ này, một chuỗi request không còn là dãy thao tác thủ công rời rạc, mà trở thành một máy trạng thái tự động có thể rẽ nhánh (xử lý hết hàng, lỗi đăng nhập) và lặp có điều kiện (polling tác vụ async). Khi bạn đã thành thạo việc để dữ liệu tự chảy qua chuỗi và điều hướng luồng theo trạng thái thực tế, bạn đã sẵn sàng để tự động hóa toàn bộ kiểm thử end-to-end và tích hợp nó vào pipeline CI/CD.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi