REST Assured in Practice: Check Status, Body, and Data in One Readable API Test
A green API test does not always mean the feature works. The response can say “201 Created” while the record in the database is wrong or missing. In my REST Assured tests, I check three things in one readable test: the status, the response body, and the data in the database. This article shows how I do it with Java, JUnit, and a simple SQL query.
1. Start in Postman, then automate
I first send the request in Postman. It is the fastest way to see the real response: status code, fields, and error messages. I also try a few negative cases, such as a missing email or an invalid format, to see how the API responds.
Get Hasan Akdogan’s stories in your inbox
Join Medium for free to get updates from this writer.
When I know what “correct” looks like, I move the same request into a REST Assured test. Postman is for exploring; the automated test is for checking it again on every build in Jenkins.
2. Share the setup in one place
Every test needs the base URL, content type, and often an auth header. Instead of repeating them, I put them in a shared RequestSpecification:
static RequestSpecification spec = new RequestSpecBuilder()
.setBaseUri(ConfigReader.get("baseUrl"))
.setContentType(ContentType.JSON)
.addHeader("Authorization", "Bearer " + TokenHelper.getToken())
.build();Now each test only contains what is special about that test.
3. Check the status and the body together
REST Assured’s given / when / then style reads almost like a test case. Here is a test that creates a user and checks the response:
@Test
void createUser_returns201_andSavesToDatabase() throws SQLException {
String email = "qa-user-" + System.currentTimeMillis() + "@test.com";
int userId =
given()
.spec(spec)
.body(Map.of("name", "QA User", "email", email))
.when()
.post("/api/users")
.then()
.statusCode(201)
.body("email", equalTo(email))
.body("id", notNullValue())
.extract().path("id");
assertUserInDatabase(userId, email);
}The unique email keeps the test independent, so it can run many times and in any order. extract() gives me the new ID for the next step.
4. Confirm the data with SQL
The API says the user was created. Now I check that the database agrees, with a simple JDBC query:
void assertUserInDatabase(int userId, String email) throws SQLException {
try (Connection conn = DbHelper.getConnection();
PreparedStatement ps = conn.prepareStatement(
"SELECT email, status FROM users WHERE id = ?")) {
ps.setInt(1, userId);
ResultSet rs = ps.executeQuery();
assertTrue(rs.next(), "User was not saved");
assertEquals(email, rs.getString("email"));
assertEquals("ACTIVE", rs.getString("status"));
}
}This catches bugs the response cannot show: a wrong default status, a missing field, or a record that was never saved. The try-with-resources block closes the connection even if an assertion fails.
5. Test the negative case too
A good API test suite also checks what should fail. If the email is missing, the API should return a clear error, and nothing should be saved:
@Test
void createUser_withoutEmail_returns400() {
given()
.spec(spec)
.body(Map.of("name", "QA User"))
.when()
.post("/api/users")
.then()
.statusCode(400)
.body("message", containsString("email"));
}I often find more bugs in these cases than in the happy path, because developers usually test the happy path first. The negative cases I tried in Postman in step 1 become these tests.
6. Keep it readable
A test is useful only if the next person understands it quickly. I keep one scenario per test and give each test a name that describes the expected result, like createUser_returns201_andSavesToDatabase. When a test fails in Jenkins, the name alone tells the team what broke.
7. Common mistakes
- Checking only the status code. A 200 or 201 with the wrong data is still a bug.
- Hard-coded test data. A fixed email fails on the second run with “already exists”.
- Asserting the whole JSON as one string. One new field breaks the test. Check the fields that matter.
- Copying setup into every test. When the token or URL changes, you fix it in many places instead of one.
Key takeaways
- Explore in Postman first, then automate the same request.
- Put shared setup in a
RequestSpecification. - Check status and body in the same
then()block. - Use SQL to confirm the data, not only the response.
- Unique test data and clear names keep tests stable and readable.
Do you check the database in your API tests, or only the response? I would like to hear how your team does it.
I’m Hasan Akdogan, a QA Automation Engineer working with Playwright, TypeScript, Selenium, and Java. More of my work: hakdogan.com · LinkedIn










