Browse the Knowledge Hub211 resources

REST Assured review: what it is, tutorial and setup
REST Assured is an open source Java library for testing HTTP APIs, with a fluent given, when, then syntax over an HTTP client and Hamcrest matchers. Tests are ordinary JUnit or TestNG tests, so API checks live in the same repository and build as the code they test. Version 6 needs Java 17 or later; 6.1.0 was released on 9 October 2026.
QAble runs this tool on client engagements. The assessment below is from that experience.
- last reviewed
- 13 October 2026
- version covered
- REST Assured 6
- licence
- Open source
At a glance
REST Assured at a glance
- Vendor
- REST Assured project
- Category
- API testing
- Licence
- Open source (Apache 2.0)
- Platforms
- JVM
- Languages
- Java, Kotlin, Groovy, Scala
- Integrates with
- JUnit, TestNG, Maven, Gradle, Allure
- First released
- 2010
- Version reviewed
- REST Assured 6
Verdict
Our verdict on REST Assured
Strengths
- Tests are plain JUnit or TestNG code, so they refactor, review and run in the same build as the service
- given, when, then reads clearly and keeps request setup, the call and assertions visibly separate
- Responses deserialise into your own classes through Jackson, Gson, JSON-B or JAXB, so tests share the service model
- The json-schema-validator module supports JSON Schema drafts up to 2020-12 from version 6.1
- Reusable request and response specifications remove repeated base URLs, headers and common assertions
- Free under Apache 2.0, with modules for Spring MockMvc and WebTestClient and Kotlin extensions
Weaknesses
- GPath body syntax differs from Jayway JsonPath, so many online examples do not work as written
- Static configuration is global; changing it during parallel runs causes intermittent failures
- JSON decimals compare as float by default, so equalTo(12.12) fails where 12.12f passes
- Version 6 requires Java 17 and Groovy 5, which can clash with older builds
- No reporting of its own; readable failure evidence needs logging setup or Allure
Best for
Java and Kotlin teams building an API regression suite that should live beside the service, run in the same Maven or Gradle build and reuse its model classes. It is our default for backend-heavy client work on the JVM because the tests are just code: they refactor with the IDE, review in pull requests and fail the build like any other test. JSON Schema validation against the published contract turns example-based checks into a much stronger guard against response drift.
Not for
Teams without Java or Kotlin skills, where Karate or a JavaScript library will be adopted faster. Exploratory work on an unfamiliar API, where Postman or Bruno is quicker. Load testing, since each request is a blocking call on a test thread and the harness becomes the bottleneck long before the server does. And services whose callers are mainly JavaScript, where SuperTest keeps the tests in the same stack.
Setup cost
Low to start: one test-scoped dependency and a JUnit test, and a first green test inside an hour. The work that decides whether the suite survives comes after: a request specification per API, a thin client class per resource so endpoints and headers never appear in tests, object mapping through Jackson, schema files, test data creation and CI. Budget one to two weeks for that foundation on a new project.
Maintenance burden
Low when layered properly and high when not. The suites we inherit in trouble almost always call given() directly in hundreds of tests with paths, headers and tokens inline, so a renamed endpoint means editing a hundred files. With a client layer the same change is one line. Upgrades are usually painless; version 6 was the exception, raising the floor to Java 17 and Groovy 5.
Honest limitations
Body paths use Groovy GPath, not the Jayway JsonPath syntax that most other tools and tutorials use, so copied examples often fail. The static RestAssured fields are shared global state, unsafe to change while tests run in parallel. Floating point values are parsed as float by default, which surprises equality checks. It is synchronous and Java-centric by design. There is no built-in reporting beyond logging, so Allure or similar is a separate integration.
How it works
What is REST Assured and how does it work?
A fluent wrapper over an HTTP client
REST Assured builds a request specification from the given() section, sends it with an embedded Apache HttpClient when you call get, post or another method, and wraps the response so that then() can assert on it. Because everything is a Java method chain, the IDE completes it, the compiler checks it and the debugger steps through it. There is no runtime of its own: the test framework, JUnit or TestNG, discovers and runs the tests, and REST Assured is a library they call. That is the source of both its fit with JVM projects and its limits elsewhere, since the suite is only as organised as the Java code around it.
GPath, not JsonPath, for body assertions
A body assertion such as body("lines[0].sku", equalTo("ABC-1")) is evaluated by REST Assured’s own JsonPath module, which uses Groovy’s GPath syntax: dot navigation, list indexes, size(), and Groovy collection methods such as find and findAll with closures. It is not the Jayway JsonPath used by Postman snippets, Karate and many libraries, so expressions starting with $ do not work. Version 6.0 moved the JsonPath evaluation itself to Java, bypassing GroovyShell, which the changelog says fixed memory leaks in long runs; the syntax is unchanged and Groovy is still on the classpath through the json-path and xml-path modules.
Object mapping uses whatever is on the classpath
Sending a Java object as a body, or calling extract().as(Order.class), relies on an object mapper found on the classpath. For JSON that can be Jackson 2, Jackson 3, Gson, Yasson or Johnzon; for XML, Jakarta EE or JAXB. REST Assured bundles none of them, so a project without one fails at the first mapping call. In practice this is a strength: if the service already uses Jackson, the tests serialise exactly as production does, and request and response classes can be shared with the application or generated from its OpenAPI document.
Static defaults and per-request specifications
Defaults such as RestAssured.baseURI, filters, authentication and config are public static fields applied to every request. They are convenient in a single-threaded suite and risky in a parallel one: changing them while tests run on several threads makes requests pick up another test’s settings, and the changelog for the next, unreleased version lists fixes for races in exactly this area. The safer pattern is to set static values once before any test starts, or not at all, and put everything else into RequestSpecification objects built with RequestSpecBuilder and passed to each request with spec().
Strengths
What it does well
Contract checks with JSON Schema
matchesJsonSchemaInClasspath validates a response against a schema file in test resources. From 6.1.0 the module reads the draft from the schema’s $schema keyword and supports draft-06, draft-07, 2019-09 and 2020-12. Schemas exported from the service’s OpenAPI document catch removed fields, changed types and broken enums across every endpoint, which hand-written field assertions rarely cover.
Reusable specifications
RequestSpecBuilder and ResponseSpecBuilder capture what every request or response shares: base URI, content type, auth headers, filters, and expectations such as status and content type. Tests then state only what is specific to them. This is the mechanism a maintainable suite is built on, and it keeps environment differences in one place.
Filters for logging, auth and reporting
A filter sees every request before it is sent and every response before it is asserted. Built-in filters log requests, responses or errors; custom ones can sign requests or refresh tokens; and Allure’s allure-rest-assured artefact provides an AllureRestAssured filter that attaches each exchange to the test report, which turns a failed CI run into readable evidence.
Testing Spring controllers without a server
The spring-mock-mvc and spring-web-test-client modules run the same given, when, then syntax against MockMvc or WebTestClient, so controller tests need no running server or network. Version 6 supports Spring Framework 7, and 6.0.1 stopped pulling an older Spring onto Spring Boot 4 classpaths. For Spring teams this gives one API style from slice tests to deployed-environment tests.
Full HTTP coverage
Path, query and form parameters, multipart uploads, cookies, sessions, proxies, mutual TLS and the usual authentication schemes are all covered, and 6.1.0 added the HTTP QUERY method. From 6.1.0, Authorization and Cookie headers are stripped by default when a redirect crosses to another host, so tokens are not leaked to redirect targets.
Pricing
REST Assured pricing and licensing
REST Assured is free and open source under the Apache 2.0 licence, with no paid edition, hosted service or feature tiers. You add it to a Maven or Gradle build as a test dependency and run it wherever your tests run. The real cost is engineering time: building the client layer, data setup and reporting around it, and the CI capacity to run the suite.
- Licence: Apache 2.0, stated in the repository. Commercial use, modification and redistribution are permitted.
- No paid tier: every module, including JSON Schema validation, Spring MockMvc support and the Kotlin extensions, is free.
- Runtime requirements: Java 17 or later and Groovy 5 from version 6.0, so very old build environments may need upgrading first.
- Hidden costs: Java skills on the test team, and the weeks spent on a service layer, test data management and reporting that the library deliberately leaves to you.
- Infrastructure: CI minutes and test environments, which scale with suite size rather than with any licence.
Checked against the vendor’s own pages on 13 October 2026. Pricing changes; confirm on the official site before buying.
Getting started
REST Assured tutorial: getting started
Setup, step by step
- Check the JDK: REST Assured 6 needs Java 17 or later.
- Add rest-assured with test scope, declared before JUnit so the right Hamcrest version wins.
- Add JUnit Jupiter and, if you will map JSON to classes, Jackson.
- Statically import RestAssured and Hamcrest Matchers in the test class.
- Write a test against a running local service and run it with mvn test or gradle test.
- Move the base URI and headers into a RequestSpecification before writing the second test.
Install
<!-- pom.xml: rest-assured first, so its Hamcrest version is used -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>6.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>6.1.3</version>
<scope>test</scope>
</dependency>A first example
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test;
class CreateOrderTest {
@Test
void createsAPendingOrder() {
given()
.baseUri("http://localhost:8080")
.contentType(ContentType.JSON)
.body("""
{"sku": "ABC-1", "quantity": 2}
""")
.when()
.post("/orders")
.then()
.statusCode(201)
// GPath syntax: no leading $, Groovy-style navigation
.body("status", equalTo("PENDING"))
.body("lines", hasSize(1))
.body("lines[0].sku", equalTo("ABC-1"));
}
}What trips people up first
Path expressions copied from elsewhere. Someone pastes $.lines[0].sku from a Postman or Jayway example and gets an invalid path error, or a filter expression returns null. REST Assured uses Groovy GPath: drop the leading $, navigate with dots and indexes, and use Groovy closures for filtering, such as lines.find { it.sku == "ABC-1" }.quantity. The second hurdle is dependency order: if JUnit or another library brings an older Hamcrest first, matchers fail with NoSuchMethodError at runtime. Declare rest-assured before JUnit in the pom, as the project’s own setup guide advises.
In practice
Using REST Assured in practice
A service layer between tests and endpoints
Structure the suite in three layers. Specifications hold what every request shares: base URI from a system property, content type, authentication and filters. Client classes, one per resource, own the paths and HTTP methods and return the raw Response. Tests call clients, assert, and never mention a URL. When an endpoint changes, one client method changes. Map bodies to records or classes rather than building JSON strings, so a renamed field is a compile error rather than a silent test change. In our experience this structure is the difference between a suite that is still trusted after two years and one that is rewritten.
public final class Specs {
public static RequestSpecification api() {
return new RequestSpecBuilder()
.setBaseUri(System.getProperty("api.baseUri", "http://localhost:8080"))
.setContentType(ContentType.JSON)
.addHeader("Authorization", "Bearer " + System.getenv("API_TOKEN"))
.build();
}
}
public final class OrdersClient {
public Response create(OrderRequest order) {
return given().spec(Specs.api()).body(order).when().post("/orders");
}
public Response get(String id) {
return given().spec(Specs.api()).pathParam("id", id).when().get("/orders/{id}");
}
}
// In a test: Jackson on the classpath maps the body both ways
Order created = orders.create(new OrderRequest("ABC-1", 2))
.then().statusCode(201)
.extract().as(Order.class);Validating responses against the contract
Field-by-field assertions check the values a test author thought of; a schema check catches everything else. Add the json-schema-validator module, export schemas from the service’s OpenAPI document into src/test/resources, and assert matchesJsonSchemaInClasspath on every response that has one. Declare $schema in each file so 6.1’s draft detection picks the right rules, or pass a JsonSchemaVersion explicitly; schemas without $schema are validated as before. Keep a small number of value assertions for business rules, such as a total equalling the sum of its lines, and let the schema guard shape and types.
// test dependency: io.rest-assured:json-schema-validator:6.1.0
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
@Test
void orderMatchesTheContract() {
orders.get(existingOrderId)
.then()
.statusCode(200)
// src/test/resources/schemas/order.json declares
// "$schema": "https://json-schema.org/draft/2020-12/schema"
.body(matchesJsonSchemaInClasspath("schemas/order.json"));
}Running the suite in GitHub Actions
Because REST Assured tests are ordinary JUnit tests, CI is a normal Maven or Gradle build. Set up the JDK with actions/setup-java, cache dependencies, pass the target environment as a system property and secrets as environment variables, and publish the Surefire reports so failures are visible without digging through logs. Run API tests in a separate Maven profile or module if they need a deployed environment, so unit tests are not blocked by an unavailable service.
# .github/workflows/api-tests.yml
name: api-tests
on: [push, pull_request]
jobs:
api:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '21'
cache: maven
- name: Run API tests against staging
run: mvn -B verify -Dapi.baseUri=https://staging.example.com
env:
API_TOKEN: ${{ secrets.STAGING_API_TOKEN }}
- uses: actions/upload-artifact@v7
if: always()
with:
name: surefire-reports
path: target/surefire-reports/Parallel execution without shared state
JUnit can run test classes or methods concurrently once parallel execution is enabled in junit-platform.properties, and API suites benefit more than most because they spend their time waiting on the network. REST Assured is safe in parallel only if nothing mutates its static fields while tests run. Set any static defaults in a single place before the run, give each test its own RequestSpecification, and create test data per test rather than sharing an order or user between tests. HttpClientConfig.reuseHttpClientInstance shares one HTTP client between requests, but the project’s changelog warns that the reused client is reconfigured by every request, so leave it off for concurrent tests.
Debugging failures and upgrading to version 6
A bare assertion failure tells you little about an API problem. Call RestAssured.enableLoggingOfRequestAndResponseIfValidationFails() once at start-up, or use log().ifValidationFails() on a specification, so the full request and response are printed only when a test fails; add the Allure filter if you publish reports. When upgrading from 5.x, move the build to Java 17 or later, check for other Groovy dependencies that conflict with Groovy 5, and update Spring modules for Spring 7 if you use them. Rerun the suite with redirects in mind: from 6.1.0 credentials are no longer forwarded to a different host on redirect.
Pitfalls
Common pitfalls
Using Jayway JsonPath syntax in body assertions
Why it happens: Most API tools and tutorials use expressions such as $.items[0].id. REST Assured evaluates GPath, so a leading $ or Jayway filter syntax is invalid or returns null.
The fix: Write GPath: items[0].id, items.size(), items.find { it.id == 7 }.name. Test complex expressions with JsonPath.from(json).get(path) in a scratch test first.
Changing RestAssured static fields inside tests
Why it happens: baseURI, filters and config are global. Setting them in one test while another runs on a different thread makes requests use the wrong settings, and failures move around between runs.
The fix: Set static defaults once before any test, or not at all. Pass a RequestSpecification to every request with spec(), and build per-test variations from it.
Decimal assertions that fail for no visible reason
Why it happens: By default JSON numbers with a fraction are parsed as float, so equalTo(12.12), a double, never matches 12.12 in the body.
The fix: Compare with a float literal such as 12.12f, or configure JsonConfig with NumberReturnType.BIG_DECIMAL for money values and compare BigDecimals.
NoSuchMethodError from Hamcrest matchers
Why it happens: JUnit or another library brought an older Hamcrest onto the classpath first, and Maven resolved that version for everything.
The fix: Declare rest-assured before JUnit in the pom, as the getting-started guide advises, or pin Hamcrest explicitly and check with mvn dependency:tree.
extract().as() failing with no object mapper
Why it happens: REST Assured does not bundle Jackson, Gson or JSON-B. Without one on the test classpath, serialising a body or mapping a response fails at run time.
The fix: Add the mapper the service already uses, Jackson 2 or 3 in most Java projects, as a test dependency so tests serialise exactly as production does.
Upgrading to 6.x and the build breaking before any test runs
Why it happens: Version 6.0 raised the minimum to Java 17 and Groovy 5, and Spring modules now expect Spring 5.3 or later. Old JDKs and conflicting Groovy versions fail at compile or class loading.
The fix: Move the build JDK first, align or exclude other Groovy dependencies, then upgrade REST Assured and rerun the suite, paying attention to redirect behaviour changed in 6.1.0.
Compared
How REST Assured compares
| Tool | Test language | Runs inside | Body query syntax | Schema validation | Licence |
|---|---|---|---|---|---|
| REST Assured | Java, Kotlin, Groovy, Scala | JUnit or TestNG on the JVM | Groovy GPath | Module, drafts up to 2020-12 | Apache 2.0 |
| Karate | Karate DSL with embedded JavaScript | JUnit 6 runner or standalone CLI | match expressions and JsonPath | Built-in fuzzy markers such as #string | MIT, commercial add-ons |
| Postman | JavaScript in the Postman sandbox | Postman app or Postman CLI | Plain JavaScript on parsed JSON | jsonSchema assertion in scripts | Proprietary, freemium |
| SuperTest | JavaScript, TypeScript | Any Node.js test framework | Plain JavaScript on parsed JSON | Through a separate library | MIT |
FAQ
Frequently asked questions
What is REST Assured?
REST Assured is an open source Java library for testing HTTP APIs, with a fluent given, when, then syntax over an HTTP client and Hamcrest matchers. Tests are ordinary JUnit or TestNG tests, so API checks live in the same repository and build as the code they test. Version 6 needs Java 17 or later; 6.1.0 was released on 9 October 2026.
Is REST Assured free?
Yes. REST Assured is open source under the Apache 2.0 licence, with no paid edition, hosted service or locked features. Every module, including JSON Schema validation, the Spring MockMvc and WebTestClient modules and the Kotlin extensions, is free. The costs are the engineering time to build a maintainable suite around it and the CI and environments the tests run on.
What changed in REST Assured 6?
Version 6.0.0, released on 12 December 2025, raised the minimum to Java 17 and Groovy 5, added Jackson 3, Yasson 3 and Johnzon 3 object mapping, supported Spring 7 in the Spring modules and moved JsonPath evaluation to Java. 6.1.0, released on 9 October 2026, added JSON Schema drafts up to 2020-12, the HTTP QUERY method, and stripping of Authorization and Cookie headers on cross-host redirects by default.
Why does my JsonPath expression not work in REST Assured?
REST Assured’s JsonPath uses Groovy’s GPath syntax, not the Jayway JsonPath syntax used by Postman examples and many other libraries. Remove the leading $ and use dot navigation and indexes, for example data.items[0].id. For filtering, use Groovy methods with closures such as items.findAll { it.price > 10 }.name. If you need Jayway syntax, extract the body as a string and evaluate it with the Jayway library separately.
REST Assured or Karate?
Choose REST Assured when the team writes Java or Kotlin, the tests should share model classes with the service, and the suite benefits from ordinary refactoring and IDE support. Choose Karate when testers are not Java developers, when readable feature files matter, or when you want mocks and performance reuse of the same scenarios in one tool. Both run on the JVM and fit Maven and Gradle builds.
Can REST Assured run tests in parallel?
Yes, through the test framework: enable JUnit Jupiter parallel execution in junit-platform.properties, or use TestNG’s parallel settings. REST Assured itself is safe in parallel only if tests do not change its static configuration while running. Keep each test’s settings in its own RequestSpecification, set any global defaults once before the run, and make test data independent so concurrent tests cannot collide.
Can REST Assured test GraphQL or SOAP?
It can send any HTTP request, so GraphQL is tested by posting a JSON body with query and variables to the endpoint and asserting on the data and errors fields. SOAP works the same way with an XML body and XmlPath or XPath assertions. There are no GraphQL- or WSDL-aware helpers, so for SOAP-heavy work a tool such as SoapUI that reads the WSDL directly may be more productive.
Is REST Assured still worth learning in 2026?
Yes, for anyone testing APIs on the JVM. It remains actively maintained, with several releases in 2026 including a new major line, and its patterns, specifications, client layers and schema validation, transfer to any code-based API framework. If your team works in JavaScript or Python, learn the equivalent library in that stack instead.
Alternatives
REST Assured alternatives worth weighing
Postman
API platform combining a request client, collections, environments, JavaScript test scripts and mock servers, with collections run in CI by the Postman CLI.
Karate
API testing framework with its own DSL, requiring no Java knowledge and bundling mocks and performance testing.
SuperTest
Node.js library for HTTP assertions, commonly used to test Express applications in process.
Resources
Where to go next
Keep going
Prepare, or get it done
Picking the wrong tool costs more than picking late.
QAble advises on toolchain decisions and then implements them, with engineers who have run these tools on real delivery. Start with a free QA audit.