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()
ingiven()
: Logs the request (method, URL, headers, body if any).log().all()
inthen()
: 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
andmvn 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, enablelog().all()
or use aLogFilter
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.