API Testing
Intermediate 14 min read API Testing

REST Assured

REST Assured is a JVM library that makes testing REST services read like natural sentences: given().when().then(). Learn the BDD-style DSL, Hamcrest matchers, schema validation and how to run suites inside Maven or Gradle builds.

REST AssuredJavaHamcrestgiven/when/thenJSONPathMaven
Introduction

What is this?

REST Assured is a JVM library for testing REST services with a BDD-style DSL: describe the request in given(), trigger the call in when(), and assert the result in then(). It ships built-in JSON/XML parsing, Hamcrest matchers, schema validation and first-class support for auth, cookies and logging. Java and Kotlin teams use it to express API behavior checks with minimal boilerplate.

Motivation

Why do you need it?

  • The given/when/then DSL reads like a spec, so tests double as readable documentation of expected behavior.
  • Built-in matchers handle nested JSON and XML assertions, schema validation and error checks out of the box.
  • First-class support for cookies, sessions and OAuth makes authenticated flows trivial to test.
  • Response logging (log().all()) shows exactly what was sent and received, cutting debugging time dramatically.
  • It integrates with JUnit, TestNG and Maven/Gradle, so API tests run inside the normal build and CI pipeline.
Think about it

Mental model

Imagine

A restaurant order slip

Think of

A REST Assured then() block

given() is how you order: table, dish, modifiers. when() is the kitchen actually cooking. then() is the waiter checking the plate matches the slip. REST Assured makes those three stages explicit so the test describes the exchange, not just the outcome.

Mechanics

How it works

  • Add the rest-assured, json-path and xml-path artifacts to your build via Maven or Gradle.
  • Configure a base URI and port (RestAssured.baseURI) once in a setup method so tests stay portable.
  • Describe the request in given(): headers, params, cookies, auth and the body.
  • Trigger the call in when(): get(), post(), put() or delete() with the endpoint path.
  • Validate the result in then(): statusCode(), body() with matchers, headers(), and extract() to reuse values.

The three-stage lifecycle of a REST Assured test.

Test class
given()
when()
Response
then()
Pass or fail
Reference

Key commands

mvn test -Dtest=AuthApiTest

Run a single REST Assured test class through Maven Surefire.

[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
gradle test --tests 'com.forge.api.AuthApiTest'

Run one test class with the Gradle test task.

mvn test -DapiBaseUrl=https://staging.example.com

Override the API base URL at runtime without editing test code.

mvn dependency:tree -Dincludes=io.rest-assured:rest-assured

Check which version of REST Assured and its transitive deps are resolved.

io.rest-assured:rest-assured:jar:5.4.0:test
mvn test -Drestassured.debug=true

Enable REST Assured debug logging across the whole suite.

Hands-on

Examples

Login, verify the response, and reuse the token

Login, verify the response, and reuse the token
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
class AuthApiTest {
@BeforeAll
static void setUp() {
RestAssured.baseURI = System.getProperty("apiBaseUrl", "https://api.example.com");
}
@Test
void loginReturnsToken() {
String token = given()
.contentType(ContentType.JSON)
.body("{\"email\":\"ada@example.com\",\"password\":\"secret\"}")
.log().all()
.when()
.post("/auth/login")
.then()
.statusCode(200)
.body("token", Matchers.not(Matchers.emptyString()))
.extract().path("token");
given()
.header("Authorization", "Bearer " + token)
.accept(ContentType.JSON)
.when()
.get("/v1/me")
.then()
.statusCode(200)
.body("email", Matchers.equalTo("ada@example.com"));
}
}

setUp reads the base URL from a system property so the same suite runs against any environment. The first call posts credentials and asserts the status and token shape, then extract().path() pulls the token out of the response so the second, authenticated request can reuse it. .log().all() prints the full exchange while you debug.

Real world

In production

  • Maven or Gradle builds run REST Assured suites in the integration-test phase before every release.
  • The same tests run against ephemeral staging environments in CI, gating deploys on API compatibility.
  • Surefire and TestNG reports feed dashboards so teams track API contract pass rate over time.
  • Teams migrate exploratory curl calls into REST Assured tests during bug triage, locking fixes in.
Guidelines

Best practices

  • Configure baseURI and basePath in a setup method, never hard-code them inside tests.
  • Give tests names that describe behavior, and keep each test focused on one outcome.
  • Reuse common assertions with RequestSpecification and ResponseSpecification instead of repeating them.
  • Use .log().all() while debugging and remove it before commit to keep CI logs readable.
  • Extract reusable values with .extract().path() rather than re-parsing JSON in every test.
Watch out

Common mistakes

  • Hard-coding a live base URL so tests hit production and pollute real data.
  • Asserting only statusCode() while ignoring headers, schema or business values in the body.
  • Forgetting to set ContentType when sending a body, which triggers 415 errors.
  • Writing one giant test method that checks everything and fails as an opaque wall of red.
Root cause analysis

Common issues

Error
java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
Root cause

Hamcrest is missing or an incompatible version is on the classpath.

Fix

Add org.hamcrest:hamcrest (2.2+) and make sure its version is compatible with your rest-assured release.

Error
The request works in Postman but returns 400 in REST Assured
Root cause

Headers or body serialization differ — typically Content-Type or parameter type mismatch.

Fix

Compare the log().all() output with the working Postman request and align Content-Type, params and body format.

Error
java.lang.IllegalArgumentException: Cannot construct instance of <type>
Root cause

Jackson cannot parse the response into the expected POJO, usually a field or type mismatch.

Fix

Use JsonPath against the raw body or align the DTO's field names and types with the actual JSON.

When things break

Debugging tips

  • Add .log().all() to given() and then() to print the full request and response on failure.
  • Use .peek() or .print() in the response chain to dump the body while debugging.
  • Read the response .statusLine() to see the raw reason phrase alongside the status code.
  • Compare against a plain curl of the same endpoint to isolate whether the bug is in the test or the API.
Interviews

Interview checkpoint

Practice

Hands-on lab

Your First REST Assured Suite in JUnit
45 min · intermediate
In progress
Objectives
  • Bootstrap a Maven project with the REST Assured dependency
  • Configure a base URI from a system property
  • Write a GET test with status and body assertions
  • Write a POST test that extracts a value from the response

Your First REST Assured Suite in JUnit

45 min · intermediate

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which method starts the response assertions in the REST Assured DSL?

2

REST Assured can only test JSON responses, not XML.

3

A POST test fails with 415 Unsupported Media Type. What is the most likely missing step?

Quick reference

Cheat sheet

Core DSL
given().header("k", "v")Add a request header
given().contentType(ContentType.JSON)Declare the body format
when().get("/path")Trigger a GET call
then().statusCode(200)Assert the status code
then().body("user.name", Matchers.equalTo("Ada"))Assert a nested JSON value
.extract().path("token")Pull a value out for reuse
Maven setup
io.rest-assured:rest-assuredCore library (scope: test)
io.rest-assured:json-schema-validatorSchema validation support
org.hamcrest:hamcrestMatchers dependency
Go deeper

Official documentation