API Hooks

Why API Hooks?

In API testing, modifying requests dynamically before sending and processing responses after receiving is essential for handling real-world scenarios. Without these capabilities, tests can become rigid and fail to address dynamic requirements. API Hooks allow you to:

  • Modify Requests Dynamically:

    • Encrypt request data before sending.
    • Apply dynamic query parameters or headers based on runtime configurations, such as prettyPrint=true.
  • Modify and Extract Response Data:

    • Decrypt encrypted responses for validation.
    • Transform XML responses into JSON for easier assertions.
    • Apply complex validations that go beyond simple assertions.

API Hooks solve these challenges by injecting custom logic at specific points in the request lifecycle, enhancing test flexibility and accuracy.


Hook Types

beforeRequest Hook

This hook runs before the request is sent, allowing you to modify the request and access contextual data.

Accessible APIs:

  • $context: Shared variables for the test flow.
  • $request: The request object (modifiable).

Example Scenario: Add Dynamic Authentication Headers

async function beforeRequest() {
  const authToken = $context.variables.authToken; // Fetch token from context
  if (!authToken) {
    throw new Error("Authentication token is missing!");
  }
  $request.headers["Authorization"] = `Bearer ${authToken}`; // Add header
}

afterResponse Hook

This hook runs after the response is received, enabling you to validate or transform data, and add assertions.

Accessible APIs:

  • $context: Shared variables for the test flow.
  • $response: The response object (modifiable).
  • $request (read-only): The original request object.
  • $addAssertionResult: Add custom assertions.

Example Scenario: Validate JWT Token Format in the Response

async function afterResponse() {
  const token = $response.body.token; // Extract token from response body
  const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/;
  if (jwtRegex.test(token)) {
    $addAssertionResult({ passed: true, message: "Valid JWT token format." });
  } else {
    $addAssertionResult({
      passed: false,
      message: "Invalid JWT token format.",
    });
  }
}

Hook Levels and Execution Order

Each level can enable multiple hooks, forming a composition pattern that allows you to design modular and reusable hooks. This approach helps break down complex logic into smaller, focused components for better maintainability and reusability.

Hooks can be defined at various levels for granular control:

  • Single API Level: Hook specific to an individual API node.
  • Test Case Level: Hook applied to all APIs in a test case.
  • Folder Level: Hook applied to all test cases in a folder.
  • Global Level (Coming Soon): Hook applied to all test cases in the project.

Execution Order:

  1. beforeRequest: Global → Folder → Test Case → API.
  2. afterResponse: API → Test Case → Folder → Global.

Coming Soon: We will support more flexible execution orders in a future release.


Examples for Each Level

Single API Level

Add a timestamp to a specific API request:

async function beforeRequest($context, $request) {
  $request.headers["X-Timestamp"] = new Date().toISOString();
}

Test Case Level

Validate all responses in a test case for successful status codes:

async function afterResponse() {
  const successCodes = [200, 201, 202, 204];
  if (successCodes.includes($response.status)) {
    $addAssertionResult({
      passed: true,
      message: `Response status ${$response.status} is successful.`
    });
  } else {
    $addAssertionResult({
      passed: false,
      message: `Unexpected status: ${$response.status}`,
    });
  }
}

Folder Level

Encrypt all request payloads in a folder before sending:

async function beforeRequest() {
  if ($request.body) {
    $request.body = $$EncryptUtils.encryptPayload(
      $request.body,
      $context.variables.encryptionKey
    );
  }
}

Tips for Effective Hook Usage

  1. Chaining Logic: Chain logic across levels by setting headers at the folder level and modifying them at the API level.
  2. Using Context Variables: Use $context to share and store data across hooks for consistent test execution.
  3. Error Handling: Use throw new Error("Message") to fail tests with clear error messages.
  4. Performance: Keep hooks lightweight and avoid unnecessary operations.
  5. Debugging: Use console.log() sparingly and remove it before production.

Registering API Hooks from External Libraries

API Hooks can be written directly within the web editor or registered from an external library. This allows developers to write hook logic in their preferred IDE, leverage AI assistance, and include dependencies from the npm ecosystem. Hooks registered from external libraries function the same way as those written in the web editor.

For more details on setting up and registering hooks from external libraries, refer to the External Library Guide.

Next Steps

Start using API Hooks to enhance your testing workflows with dynamic modifications and validations. Experiment with different levels to optimize your test automation strategies.