API Testing

REST API and GraphQL testing capabilities

API Testing

TestFlowKit provides comprehensive backend testing capabilities for REST APIs and GraphQL endpoints.

REST API Testing

Configuration

Configure your REST API in the apis section of config.yml:

apis:
  default_timeout: 10000  # Default timeout for all APIs in milliseconds
  
  definitions:
    my_api:  # API name - use this to reference the API in tests
      type: rest
      base_url: "https://api.example.com"
      
      default_headers:
        Content-Type: "application/json"
        Accept: "application/json"
      
      endpoints:
        get_users:
          method: GET
          path: "/users"
        
        get_user:
          method: GET
          path: "/users/{id}"
        
        create_user:
          method: POST
          path: "/users"
        
        update_user:
          method: PUT
          path: "/users/{id}"
        
        delete_user:
          method: DELETE
          path: "/users/{id}"

You can define multiple REST APIs in the same configuration:

apis:
  definitions:
    users_api:
      type: rest
      base_url: "https://api.example.com"
      endpoints:
        get_users:
          method: GET
          path: "/users"
    
    products_api:
      type: rest
      base_url: "https://products.example.com"
      endpoints:
        get_products:
          method: GET
          path: "/products"

Basic Requests

GET Request

Scenario: Fetch user list
  Given I prepare a request to "my_api.get_users"
  When I send the request
  Then the response status code should be 200
  And the response should contain "users"

Note: The syntax is "api_name.endpoint_name" where:

  • api_name matches the key in your apis.definitions section
  • endpoint_name matches the endpoint key within that API

POST Request

Scenario: Create new user
  Given I prepare a request to "my_api.create_user"
  And I set the request body to:
    """
    {
      "name": "John Doe",
      "email": "john@example.com"
    }
    """
  When I send the request
  Then the response status code should be 201
  And the response JSON path "data.name" should be "John Doe"

PUT Request

Scenario: Update user
  Given I prepare a request to "my_api.update_user"
  And I set the following path parameters:
    | id | 123 |
  And I set the request body to:
    """
    {
      "name": "Jane Doe"
    }
    """
  When I send the request
  Then the response status code should be 200

DELETE Request

Scenario: Delete user
  Given I prepare a request to "my_api.delete_user"
  And I set the following path parameters:
    | id | 123 |
  When I send the request
  Then the response status code should be 204

Path Parameters

# Single parameter
Given I prepare a request to "my_api.get_user"
And I set the following path parameters:
  | id | 456 |
When I send the request

# Multiple parameters
Given I prepare a request to "my_api.get_comment"
And I set the following path parameters:
  | postId    | 123 |
  | commentId | 789 |
When I send the request

Query Parameters

Given I prepare a request to "my_api.get_users"
And I set the following query parameters:
  | page     | 1     |
  | limit    | 10    |
  | status   | active |
  | sort     | name   |
When I send the request

Request Headers

# Set individual header
Given I prepare a request to "my_api.protected_endpoint"
And I set the request header "Authorization" to "Bearer {{auth_token}}"
When I send the request

# Set multiple headers
Given I prepare a request to "my_api.api_endpoint"
And I set the following request headers:
  | Authorization | Bearer {{token}} |
  | X-API-Key     | my-api-key       |
  | Accept-Language | en-US          |
When I send the request

Note: Headers set in the step will be merged with default_headers from the API configuration.

Request Body

JSON Body

Given I prepare a request to "my_api.create_product"
And I set the request body to:
  """
  {
    "name": "Product Name",
    "price": 99.99,
    "category": "Electronics",
    "inStock": true,
    "tags": ["new", "featured"]
  }
  """
When I send the request

Form Data

Given I prepare a request to "my_api.submit_form"
And I set the form data to:
  | name  | John Doe     |
  | email | john@example.com |
  | file  | @/path/to/file.pdf |
When I send the request

Response Assertions

Status Code

Then the response status code should be 200
Then the response status code should be 201
Then the response status code should be 404
Then the response status code should be 500

Response Body

# Contains text
Then the response should contain "success"

# JSON path assertions
Then the response JSON path "data.id" should be "123"
Then the response JSON path "data.name" should be "John Doe"
Then the response JSON path "data.active" should be "true"
Then the response JSON path "data.items.length" should be "5"

# JSON path existence
Then the response JSON path "data.email" should exist
Then the response JSON path "data.password" should not exist

Response Headers

Then the response header "Content-Type" should be "application/json"
Then the response header "X-Request-Id" should exist

Response Time

Then the response time should be less than 1000 milliseconds
Then the response time should be less than 2 seconds

Extracting Data

Store response data in variables for later use:

# Extract from JSON path
When I send the request
And I store the JSON path "data.id" from the response into "user_id" variable
And I store the JSON path "data.token" from the response into "auth_token" variable

# Use extracted data
Given I prepare a request to "my_api.get_user"
And I set the following path parameters:
  | id | {{user_id}} |
And I set the request header "Authorization" to "Bearer {{auth_token}}"

GraphQL Testing

Configuration

Configure your GraphQL API in the apis section of config.yml:

apis:
  definitions:
    my_graphql_api:  # API name - use this to reference the API in tests
      type: graphql
      endpoint: "https://api.example.com/graphql"
      
      default_headers:
        Content-Type: "application/json"
      
      operations:
        get_user:
          type: query
          operation: "graphql/queries/get_user.graphql"
        create_post: 
          type: mutation
          operation: "graphql/mutations/create_post.graphql"

You can define both REST and GraphQL APIs together:

apis:
  definitions:
    rest_api:
      type: rest
      base_url: "https://api.example.com"
      endpoints:
        get_users:
          method: GET
          path: "/users"
    
    graphql_api:
      type: graphql
      endpoint: "https://api.example.com/graphql"
      operations:
        get_user: "graphql/queries/get_user.graphql"

Query Files

Create .graphql files for your operations:

# graphql/queries/get_user.graphql
query GetUser($id: ID!) {
  user(id: $id) {
    id
    name
    email
    posts {
      id
      title
    }
  }
}
# graphql/mutations/create_post.graphql
mutation CreatePost($input: CreatePostInput!) {
  createPost(input: $input) {
    id
    title
    content
    author {
      name
    }
  }
}

Executing Queries

Scenario: Fetch user data
  Given I prepare a request to "my_graphql_api.get_user"
  And I set the GraphQL variables to:
    """
    {
      "id": "123"
    }
    """
  When I send the GraphQL request
  Then the response status code should be 200
  And the response JSON path "data.user.name" should be "John Doe"

Note: The same unified syntax works for both REST and GraphQL - TestFlowKit automatically detects the API type from your configuration.

Executing Mutations

Scenario: Create a new post
  Given I prepare a request to "my_graphql_api.create_post"
  And I set the GraphQL variables to:
    """
    {
      "input": {
        "title": "My New Post",
        "content": "This is the content"
      }
    }
    """
  When I send the GraphQL request
  Then the response status code should be 200
  And the response JSON path "data.createPost.id" should exist
  And I store the JSON path "data.createPost.id" from the response into "post_id" variable

Authentication Patterns

Bearer Token

Background:
  Given I prepare a request to "my_api.login"
  And I set the request body to:
    """
    {
      "email": "user@example.com",
      "password": "password123"
    }
    """
  When I send the request
  And I store the JSON path "token" from the response into "auth_token" variable

Scenario: Access protected resource
  Given I prepare a request to "my_api.protected_data"
  And I set the request header "Authorization" to "Bearer {{auth_token}}"
  When I send the request
  Then the response status code should be 200

API Key

Scenario: Request with API key
  Given I prepare a request to "external_api.some_endpoint"
  And I set the request header "X-API-Key" to "{{api_key}}"
  When I send the request
  Then the response status code should be 200

Setting Default Headers

You can configure default headers (like authorization) in your API definition:

apis:
  definitions:
    protected_api:
      type: rest
      base_url: "https://api.example.com"
      default_headers:
        Authorization: "Bearer {{api_token}}"
        X-API-Key: "{{api_key}}"
      endpoints:
        get_data:
          method: GET
          path: "/data"

These headers will be automatically included in all requests to this API.

Best Practices

1. Use Descriptive API and Endpoint Names

# Good
apis:
  definitions:
    user_management_api:
      type: rest
      base_url: "https://api.example.com"
      endpoints:
        create_user_account:
          method: POST
          path: "/users"

# Bad
apis:
  definitions:
    api1:
      type: rest
      base_url: "https://api.example.com"
      endpoints:
        post1:
          method: POST
          path: "/users"

2. Validate Response Structure

# Verify all important fields
Then the response status code should be 200
And the response JSON path "data.id" should exist
And the response JSON path "data.name" should be "Expected Name"
And the response JSON path "data.email" should exist

3. Chain API Calls Appropriately

Scenario: Full CRUD workflow
  # Create
  Given I prepare a request to "my_api.create_item"
  And I set the request body to:
    """
    {"name": "Test Item"}
    """
  When I send the request
  And I store the JSON path "data.id" from the response into "item_id" variable
  Then the response status code should be 201

  # Read
  Given I prepare a request to "my_api.get_item"
  And I set the following path parameters:
    | id | {{item_id}} |
  When I send the request
  Then the response status code should be 200

  # Update
  Given I prepare a request to "my_api.update_item"
  And I set the following path parameters:
    | id | {{item_id}} |
  And I set the request body to:
    """
    {"name": "Updated Item"}
    """
  When I send the request
  Then the response status code should be 200

  # Delete
  Given I prepare a request to "my_api.delete_item"
  And I set the following path parameters:
    | id | {{item_id}} |
  When I send the request
  Then the response status code should be 204

Next Steps