Introduction

In our REST Assured series, we’ve explored topics like Hamcrest Matchers, JSON Schema Validation, and File Uploads and File Downloads, equipping you with tools to build robust API tests. Now, we’ll dive into Request and Response Logging, a vital feature for debugging and documenting API interactions. This guide demonstrates how to log HTTP requests and responses in REST Assured, with practical examples and best practices. It’s designed for beginners and experienced developers, ensuring you can troubleshoot tests effectively.

Key Point: Request and Response Logging in REST Assured provides visibility into HTTP interactions, aiding debugging, test verification, and documentation.

What is Request and Response Logging?

Logging in REST Assured involves capturing details of HTTP requests (e.g., headers, body, URL) and responses (e.g., status code, headers, body) during test execution. Logging is essential for:

  • Debugging: Identifying why a test fails by inspecting request/response data.
  • Documentation: Recording API interactions for reporting or auditing.
  • Verification: Ensuring requests are correctly formed before sending.

REST Assured offers built-in logging methods (e.g., log().all()), filters (e.g., LogFilter), and custom logging to files or external systems. We’ll use https://jsonplaceholder.typicode.com for basic logging examples and https://httpbin.org for scenarios involving headers or authentication. Examples will cover console logging, file logging, and integration with Allure reports.

Setting Up for Logging

We’ll set up a Maven project with REST Assured, JUnit, and Allure for reporting, consistent with previous posts. No additional dependencies are needed for basic logging, but we’ll use java.util.logging for file-based logging examples.

Here’s the pom.xml, styled with your preferred Blogger format for XML syntax highlighting:



    4.0.0
    com.example
    rest-assured-tests
    1.0-SNAPSHOT

    
        11
        2.27.0
        1.9.22
    

    
        
            io.rest-assured
            rest-assured
            5.4.0
            test
        
        
            org.junit.jupiter
            junit-jupiter
            5.10.2
            test
        
        
            org.hamcrest
            hamcrest
            2.2
            test
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.15.2
            test
        
        
            io.qameta.allure
            allure-junit5
            ${allure.version}
            test
        
    

    
        
            
                org.apache.maven.plugins
                maven-surefire-plugin
                3.2.5
                
                    
                        -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                    
                
                
                    
                        org.aspectj
                        aspectjweaver
                        ${aspectj.version}
                    
                
            
            
                io.qameta.allure
                allure-maven
                2.12.0
                
                    ${allure.version}
                
            
        
    

No additional setup is required for https://jsonplaceholder.typicode.com or https://httpbin.org. For file logging, we’ll create temporary log files programmatically.

Logging Requests and Responses

Let’s explore how to log requests and responses using REST Assured’s built-in methods, filters, and custom logging.

Example 1: Basic Logging with log().all()

Log all request and response details to the console.


import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Request and Response Logging")
public class BasicLoggingTest {

    @Test
    @Description("Test basic request and response logging")
    public void testBasicLogging() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        given()
            .log().all()
        .when()
            .get("/posts/1")
        .then()
            .log().all()
            .statusCode(200)
            .body("id", equalTo(1));
    }
}

Explanation:

  • log().all() in given(): Logs the request (method, URL, headers, body if any).
  • log().all() in then(): Logs the response (status, headers, body).
  • Output is printed to the console, useful for quick debugging.
Important: log().all() can generate verbose output. Use selectively in production tests to avoid clutter.

Example 2: Selective Logging

Log specific parts of the request and response (e.g., headers, body).


import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Request and Response Logging")
public class SelectiveLoggingTest {

    @Test
    @Description("Test selective logging of headers and body")
    public void testSelectiveLogging() {
        RestAssured.baseURI = "https://httpbin.org";

        given()
            .header("X-Custom-Header", "TestValue")
            .log().headers()
            .log().body()
        .when()
            .get("/get")
        .then()
            .log().status()
            .log().headers()
            .statusCode(200)
            .body("headers.X-Custom-Header", equalTo("TestValue"));
    }
}

Explanation:

  • log().headers(): Logs only the request or response headers.
  • log().body(): Logs only the request or response body.
  • log().status(): Logs only the response status line.
  • Selective logging reduces console clutter.

Example 3: Logging with LogFilter

Use a LogFilter to log request and response details.


import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.filter.log.LogFilter;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Request and Response Logging")
public class LogFilterTest {

    @Test
    @Description("Test logging with LogFilter")
    public void testLogFilter() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        given()
            .filter(new LogFilter())
        .when()
            .get("/posts/1")
        .then()
            .statusCode(200)
            .body("id", equalTo(1));
    }
}

Explanation:

  • LogFilter: A reusable filter that logs both request and response details.
  • Similar to log().all() but can be applied globally or across multiple tests.
  • Output is printed to the console.
Pro Tip: Use LogFilter for consistent logging across tests, especially in large test suites.

Example 4: Custom Logging to a File

Log request and response details to a file using a custom filter.


import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.filter.Filter;
import io.restassured.filter.FilterContext;
import io.restassured.response.Response;
import io.restassured.specification.FilterableRequestSpecification;
import io.restassured.specification.FilterableResponseSpecification;
import org.junit.jupiter.api.Test;
import java.io.*;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Request and Response Logging")
public class FileLoggingTest {

    public static class FileLoggingFilter implements Filter {
        private final File logFile;

        public FileLoggingFilter(File logFile) {
            this.logFile = logFile;
        }

        @Override
        public Response filter(FilterableRequestSpecification requestSpec,
                               FilterableResponseSpecification responseSpec,
                               FilterContext ctx) {
            try (PrintWriter writer = new PrintWriter(new FileWriter(logFile, true))) {
                writer.println("Request: " + requestSpec.getMethod() + " " + requestSpec.getURI());
                writer.println("Headers: " + requestSpec.getHeaders());
                writer.println("Body: " + requestSpec.getBody());
                writer.println("---");

                Response response = ctx.next(requestSpec, responseSpec);

                writer.println("Response Status: " + response.getStatusLine());
                writer.println("Headers: " + response.getHeaders());
                writer.println("Body: " + response.getBody().asString());
                writer.println("===");
                return response;
            } catch (IOException e) {
                throw new RuntimeException("Failed to log to file", e);
            }
        }
    }

    @Test
    @Description("Test custom logging to a file")
    public void testFileLogging() throws IOException {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        File tempLogFile = File.createTempFile("api-log", ".txt");

        given()
            .filter(new FileLoggingFilter(tempLogFile))
        .when()
            .get("/posts/1")
        .then()
            .statusCode(200)
            .body("id", equalTo(1));

        // Clean up (optional, keep file for inspection if needed)
        tempLogFile.delete();
    }
}

Explanation:

  • FileLoggingFilter: Logs request and response details to a file.
  • File.createTempFile(...): Creates a temporary log file for portability.
  • Logs include method, URI, headers, body, status, and response content.

Example 5: Logging with Authentication

Log requests and responses for an authenticated endpoint using a mock Bearer token.


import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Request and Response Logging")
public class AuthLoggingTest {

    @Test
    @Description("Test logging with Bearer token authentication")
    public void testAuthLogging() {
        RestAssured.baseURI = "https://httpbin.org";

        given()
            .header("Authorization", "Bearer my-bearer-token")
            .log().all()
        .when()
            .get("/get")
        .then()
            .log().all()
            .statusCode(200)
            .body("headers.Authorization", equalTo("Bearer my-bearer-token"));
    }
}

Explanation:

  • Logs the Authorization header in the request and response.
  • Useful for debugging authentication issues.
  • log().all() captures all details, including sensitive headers (use cautiously in production).

Integrating with Allure Reporting

Document logging details in Allure reports by attaching request and response data.


import io.qameta.allure.Allure;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Request and Response Logging")
public class AllureLoggingTest {

    @Test
    @Description("Test logging with Allure reporting")
    public void testAllureLogging() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        Response response = given()
            .log().all()
        .when()
            .get("/posts/1")
        .then()
            .log().all()
            .statusCode(200)
            .body("id", equalTo(1))
            .extract().response();

        Allure.addAttachment("Request URI", "text/plain", given().getRequestSpecification().getURI(), ".txt");
        Allure.addAttachment("Response Body", "application/json", response.asString(), ".json");
    }
}

Explanation:

  • Allure.addAttachment: Attaches the request URI and response body to the Allure report.
  • Run mvn clean test and mvn allure:serve to view the report.
Pro Tip: Attach only essential data to Allure reports to keep them concise and avoid overwhelming readers.

Integrating with CI/CD

Add logging-based tests to a GitHub Actions pipeline for automation.

Create or update .github/workflows/ci.yml:


name: REST Assured CI Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up JDK 11
        uses: actions/setup-java@v4
        with:
          java-version: '11'
          distribution: 'temurin'

      - name: Cache Maven dependencies
        uses: actions/cache@v4
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: ${{ runner.os }}-maven-

      - name: Run tests
        run: mvn clean test

      - name: Generate Allure report
        run: mvn allure:report

      - name: Upload Allure results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: allure-results
          path: target/allure-results

      - name: Publish Allure report
        if: always()
        uses: simple-elf/allure-report-action@v1.7
        with:
          allure_results: target/allure-results
          gh_pages: gh-pages
          allure_report: allure-report

      - name: Deploy report to GitHub Pages
        if: always()
        uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: allure-report

Explanation:

  • Runs logging-based tests with mvn clean test.
  • Publishes Allure reports to GitHub Pages for visibility.

Tips for Beginners

  • Use Selective Logging: Log only necessary parts (e.g., headers, body) to reduce noise.
  • Protect Sensitive Data: Avoid logging sensitive information like tokens or passwords in production.
  • Integrate with Filters: Use LogFilter or custom filters for reusable logging logic.
  • Persist Logs for Debugging: Save logs to files or Allure reports for post-test analysis.
Troubleshooting Tip: If a test fails, enable log().all() or use a LogFilter to capture full request and response details, then inspect for mismatches or errors.

What’s Next?

This post enhances our REST Assured series by covering Request and Response Logging, a key tool for debugging and documenting API tests. To continue your learning, consider exploring:

  • GraphQL Testing: Testing GraphQL APIs with REST Assured.
  • Advanced Allure Reporting: Customizing reports with environments and categories.
  • End-to-End Testing: Combining REST Assured with Selenium for UI and API testing.
Stay tuned for more testing tutorials!