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.
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.
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.
Mental model
A restaurant order slip
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.
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.
Key commands
mvn test -Dtest=AuthApiTestRun 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.comOverride the API base URL at runtime without editing test code.
mvn dependency:tree -Dincludes=io.rest-assured:rest-assuredCheck 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=trueEnable REST Assured debug logging across the whole suite.
Examples
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.
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.
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.
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.
Common issues
java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribingHamcrest is missing or an incompatible version is on the classpath.
Add org.hamcrest:hamcrest (2.2+) and make sure its version is compatible with your rest-assured release.
The request works in Postman but returns 400 in REST AssuredHeaders or body serialization differ — typically Content-Type or parameter type mismatch.
Compare the log().all() output with the working Postman request and align Content-Type, params and body format.
java.lang.IllegalArgumentException: Cannot construct instance of <type>Jackson cannot parse the response into the expected POJO, usually a field or type mismatch.
Use JsonPath against the raw body or align the DTO's field names and types with the actual JSON.
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.
Interview checkpoint
Hands-on lab
- 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
Quick quiz
Which method starts the response assertions in the REST Assured DSL?
REST Assured can only test JSON responses, not XML.
A POST test fails with 415 Unsupported Media Type. What is the most likely missing step?
Cheat sheet
given().header("k", "v")Add a request headergiven().contentType(ContentType.JSON)Declare the body formatwhen().get("/path")Trigger a GET callthen().statusCode(200)Assert the status codethen().body("user.name", Matchers.equalTo("Ada"))Assert a nested JSON value.extract().path("token")Pull a value out for reuseio.rest-assured:rest-assuredCore library (scope: test)io.rest-assured:json-schema-validatorSchema validation supportorg.hamcrest:hamcrestMatchers dependency