- Home
- REST Assured Tutorial
REST Assured
API Testing A to Z
Master REST Assured from scratch — setup, requests, assertions, authentication, and real-world best practices. Built for beginners and intermediate testers.
Think of it this way: when you test a website manually, you open a browser, go to a URL, and check what shows up. REST Assured does the same thing — but for APIs, and automatically.
Key Facts About REST Assured
| Property | Details |
|---|---|
| Language | Java |
| Created by | Johan Haleby |
| Type | Open-source library (Apache 2.0 license) |
| Used for | Testing REST APIs — GET, POST, PUT, DELETE, PATCH |
| Works with | TestNG, JUnit, Maven, Gradle |
| GitHub Stars | 6,700+ stars — widely used in enterprise projects |
| Official site | rest-assured.io |
Why REST Assured? What makes it special?
- ✓Readable syntax (BDD style): Uses Given/When/Then format — your test reads like English.
- ✓No complex setup: Just add a Maven dependency and you're ready to write tests.
- ✓Built-in JSON & XML support: Parse, extract, and validate response data easily.
- ✓Works with all HTTP methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS.
- ✓Authentication support: Basic Auth, OAuth, OAuth2, Bearer Token — built in.
- ✓Integrates with CI/CD: Works with Jenkins, GitHub Actions, and any pipeline tool.
Before writing any test, you must understand what a REST API is and how HTTP works. This is the foundation on which REST Assured is built.
HTTP Methods — The 5 You Must Know
| Method | Purpose | Example |
|---|---|---|
| GET | Read / Fetch data | Get list of all users |
| POST | Create new data | Create a new user account |
| PUT | Update (full replace) | Update all details of a user |
| PATCH | Update (partial) | Update only the email of a user |
| DELETE | Remove data | Delete a user by ID |
HTTP Status Codes — What Do They Mean?
| Code | Meaning | When you see it |
|---|---|---|
| 200 OK | Success | GET request fetched data correctly |
| 201 Created | Created | POST request created new resource |
| 204 No Content | Success, no body | DELETE was successful |
| 400 Bad Request | Client error | You sent wrong/missing data |
| 401 Unauthorized | Not authenticated | No token or wrong credentials |
| 403 Forbidden | No permission | Token valid but no access rights |
| 404 Not Found | Resource missing | Wrong endpoint or ID doesn't exist |
| 500 Internal Server Error | Server crashed | Bug on the server side |
What is JSON? (REST Assured uses it a lot)
JSON (JavaScript Object Notation) is the most common format for sending and receiving data in REST APIs. It is easy to read and write.
{
"id": 1,
"name": "Rahul Sharma",
"email": "rahul@example.com",
"role": "tester",
"active": true
}
REST Assured is a Java library. You add it to your project using Maven or Gradle. Below is the recommended Maven setup using TestNG as the test framework.
Install Java JDK 11+
Download from adoptium.net. Verify: java -version in terminal.
Install IntelliJ IDEA or Eclipse
IntelliJ Community (free) is recommended for beginners. Download from jetbrains.com.
Create a Maven Project
In IntelliJ: File → New Project → Maven. This creates a pom.xml file automatically.
Add REST Assured dependencies
Paste the dependencies shown below inside your pom.xml file.
Maven Dependencies (pom.xml)
<!-- Add inside <dependencies> tag in pom.xml --> <!-- REST Assured --> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>5.4.0</version> <scope>test</scope> </dependency> <!-- TestNG --> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.9.0</version> <scope>test</scope> </dependency> <!-- JSON Schema Validation (optional but useful) --> <dependency> <groupId>io.rest-assured</groupId> <artifactId>json-schema-validator</artifactId> <version>5.4.0</version> </dependency>
Let's write your very first API test. We will use the free public API https://reqres.in — a dummy REST API designed for testing. No sign-up needed.
import io.restassured.RestAssured; import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*; import org.testng.annotations.Test; public class FirstTest { @Test public void testGetUser() { given() .log().all() // log the request details .when() .get("https://reqres.in/api/users/2") .then() .log().all() // log the response details .statusCode(200) // assert status code is 200 .body("data.email", containsString("janet")); } }
REST Assured uses the BDD (Behavior Driven Development) syntax. This is the heart of REST Assured — every test you write will follow this structure.
given()
Set up the request — headers, params, body, auth, base URL.
when()
Send the actual HTTP request — get(), post(), put(), delete().
then()
Verify the response — status code, body values, headers.
given() .baseUri("https://reqres.in") .header("Content-Type", "application/json") .when() .get("/api/users?page=2") .then() .statusCode(200) .body("page", equalTo(2)) .body("data.size()", greaterThan(0));
REST Assured supports all HTTP methods. Here are examples for each, using the reqres.in public test API.
GET — Fetch Data
@Test public void getUsers() { given() .when() .get("https://reqres.in/api/users/1") .then() .statusCode(200) .body("data.id", equalTo(1)); }
POST — Create Data
@Test public void createUser() { String body = "{ \"name\": \"Rahul\", \"job\": \"tester\" }"; given() .header("Content-Type", "application/json") .body(body) .when() .post("https://reqres.in/api/users") .then() .statusCode(201) .body("name", equalTo("Rahul")); }
PUT — Full Update
@Test public void updateUser() { String body = "{ \"name\": \"Rahul Updated\", \"job\": \"senior tester\" }"; given() .header("Content-Type", "application/json") .body(body) .when() .put("https://reqres.in/api/users/2") .then() .statusCode(200) .body("name", equalTo("Rahul Updated")); }
DELETE — Remove Data
@Test public void deleteUser() { given() .when() .delete("https://reqres.in/api/users/2") .then() .statusCode(204); // 204 means deleted, no content returned }
Most real-world APIs require you to pass query parameters, path parameters, and headers with your requests. REST Assured makes all of these easy.
Query Parameters
Query parameters appear after ? in the URL. Example: /api/users?page=2&per_page=5
given() .queryParam("page", 2) .queryParam("per_page", 5) .when() .get("https://reqres.in/api/users") .then() .statusCode(200) .body("page", equalTo(2));
Path Parameters
Path parameters are part of the URL itself. Example: /api/users/{userId}
given() .pathParam("userId", 3) .when() .get("https://reqres.in/api/users/{userId}") .then() .statusCode(200) .body("data.id", equalTo(3));
Headers
given() .header("Content-Type", "application/json") .header("Accept", "application/json") .header("x-api-key", "your-api-key-here") .when() .get("https://api.example.com/products") .then() .statusCode(200);
When creating or updating data, you need to send a request body — usually in JSON format. REST Assured gives you multiple ways to do this.
Method 1: Plain String Body
String requestBody = "{" + "\"name\": \"Priya\"," + "\"job\": \"QA Engineer\"" + "}"; given() .contentType("application/json") .body(requestBody) .when() .post("https://reqres.in/api/users") .then() .statusCode(201);
Method 2: HashMap Body (Recommended)
import java.util.HashMap; HashMap<String, String> map = new HashMap<>(); map.put("name", "Priya"); map.put("job", "QA Engineer"); given() .contentType("application/json") .body(map) .when() .post("https://reqres.in/api/users") .then() .statusCode(201) .body("name", equalTo("Priya"));
REST Assured uses Hamcrest matchers to write assertions. Hamcrest is a matching library that provides human-readable assertion methods.
Common Hamcrest Matchers
| Matcher | What it checks | Example |
|---|---|---|
| equalTo(x) | Exact match | .body("name", equalTo("Rahul")) |
| containsString(x) | String contains | .body("email", containsString("@")) |
| not(x) | Negation | .body("role", not("admin")) |
| hasSize(n) | Collection size | .body("data", hasSize(6)) |
| greaterThan(n) | Value comparison | .body("total", greaterThan(10)) |
| lessThan(n) | Value comparison | .body("count", lessThan(100)) |
| notNullValue() | Not null | .body("id", notNullValue()) |
| hasItem(x) | Array contains item | .body("tags", hasItem("java")) |
given() .when() .get("https://reqres.in/api/users?page=1") .then() .statusCode(200) .body("page", equalTo(1)) .body("per_page", equalTo(6)) .body("data", hasSize(6)) .body("data[0].email", containsString("@")) .body("data[0].id", notNullValue()) .body("total", greaterThan(5));
Sometimes you don't just want to verify a value — you want to extract it and use it in the next test (like extracting a token from a login response). REST Assured makes this simple.
import io.restassured.response.Response; @Test public void extractUserData() { Response response = given() .when() .get("https://reqres.in/api/users/2") .then() .statusCode(200) .extract().response(); // Extract individual values String email = response.jsonPath().getString("data.email"); int id = response.jsonPath().getInt("data.id"); String name = response.jsonPath().getString("data.first_name"); System.out.println("Email: " + email); System.out.println("ID: " + id); System.out.println("Name: " + name); }
Chain Extraction (Shorter syntax)
String token = given() .contentType("application/json") .body("{ \"email\": \"eve.holt@reqres.in\", \"password\": \"cityslicka\" }") .when() .post("https://reqres.in/api/login") .then() .statusCode(200) .extract().path("token"); // extract the token directly System.out.println("Token: " + token);
Most production APIs require authentication. REST Assured has built-in support for the most common authentication methods.
1. Basic Authentication
given() .auth().basic("username", "password") .when() .get("https://api.example.com/profile") .then() .statusCode(200);
2. Bearer Token (most common)
String token = "eyJhbGciOiJIUzI1NiJ9..."; // JWT token given() .header("Authorization", "Bearer " + token) .when() .get("https://api.example.com/dashboard") .then() .statusCode(200);
3. OAuth 2.0
given() .auth().oauth2("your-oauth2-access-token") .when() .get("https://api.example.com/data") .then() .statusCode(200);
In real projects, you don't want to repeat the base URL and headers in every test. RequestSpecification lets you define common settings once and reuse them everywhere.
Setting Base URI globally
import io.restassured.RestAssured; import org.testng.annotations.BeforeClass; public class BaseTest { @BeforeClass public void setup() { // Set once, used in all tests in this class RestAssured.baseURI = "https://reqres.in"; RestAssured.basePath = "/api"; } }
RequestSpecification — Reusable Config
import io.restassured.specification.RequestSpecification; import io.restassured.builder.RequestSpecBuilder; RequestSpecification spec = new RequestSpecBuilder() .setBaseUri("https://reqres.in") .setBasePath("/api") .addHeader("Content-Type", "application/json") .addHeader("Authorization", "Bearer " + token) .build(); // Use in any test: given(spec) .when() .get("/users/1") // base URL is already set in spec .then() .statusCode(200);
When your test fails, you need to understand what exactly was sent and received. REST Assured's logging features make debugging very easy.
| Log Method | What it logs |
|---|---|
| .log().all() | Full request or response (most used for debugging) |
| .log().body() | Only the request or response body |
| .log().headers() | Only headers |
| .log().status() | Only status code and status line |
| .log().ifError() | Logs only when the test fails (best for CI pipelines) |
| .log().ifValidationFails() | Logs only when an assertion fails |
given() .log().all() // log everything in the request .header("Accept", "application/json") .when() .get("https://reqres.in/api/users/2") .then() .log().ifValidationFails() // log response only if test fails .statusCode(200);
Following best practices from day one will make you job-ready and your tests maintainable, scalable, and professional.
Recommended Project Structure
src/ ├── test/ │ ├── java/ │ │ ├── base/ │ │ │ └── BaseTest.java ← RequestSpec, setup, teardown │ │ ├── tests/ │ │ │ ├── UserTests.java ← Actual test methods │ │ │ └── AuthTests.java │ │ ├── utils/ │ │ │ └── ConfigReader.java ← Read config.properties │ │ └── pojo/ │ │ └── User.java ← POJO classes for request/response │ └── resources/ │ ├── config.properties ← base URL, credentials │ └── testng.xml ← TestNG suite configuration └── pom.xml
Top 10 Best Practices
- 1Use RequestSpecification — Never repeat base URL and headers in every test.
- 2Store configs in properties file — Don't hardcode URLs, tokens, or credentials in test code.
- 3Use POJO classes — Map request/response JSON to Java objects using Jackson or Gson for cleaner code.
- 4One assertion per test (where possible) — Makes failures easier to identify.
- 5Use @BeforeClass / @AfterClass — Set up and tear down test data cleanly.
- 6Use .log().ifValidationFails() — Not .log().all() in committed code.
- 7Data-driven with @DataProvider — Run same test with multiple inputs using TestNG DataProvider.
- 8Name tests clearly — e.g. verifyGetUserReturns200WhenValidId(), not test1().
- 9Integrate with Allure or ExtentReports — Generate beautiful HTML reports for stakeholders.
- 10Integrate with CI/CD — Run tests automatically on Jenkins or GitHub Actions on every code push.
Ready to advance your QA career? 🚀
Hands-on QA training covering REST Assured, Selenium, Playwright, Postman, JIRA, Manual Testing & more — taught by industry practitioners.
Visit stadsolution.com →