About this lesson
REST Assured 400 Bad Request: read the list of validation errors with getList()
Learn REST AssuredIntermediatePOST Requests
How it works
A good API does not stop at the first problem in a payload. It checks every rule and returns all the failures together, so a client can fix them in one pass. testkru does this on /validate/json: an empty name and a missing email produce status 400, valid set to false, and an errors array with one human-readable message per broken rule, name first and email second.
In REST Assured a 400 is not an exception. The Response object holds whatever came back, so you can read the status with getStatusCode() and parse the error body exactly as you would a success. Only an assertion such as then().statusCode(200) turns an unexpected status into a failure.
JSON arrays map to Java lists. jsonPath().getList("errors") returns a List you can size and loop over, and the overload that takes String.class gives you a typed List<String>. For assertions, Hamcrest offers hasSize() to pin the count and hasItem() with containsString() to check that one message mentions a given field.
About the assignment
Trigger both validation rules at once by sending a payload whose name is blank and which has no email, then report the status, the flag, how many errors came back and each message on its own line.
What you will do
- POST the starter payload, a single empty
name, to/validate/jsonwith the JSON content type. - Print the status code after
Status:and the booleanvalidfield afterValid:. - Pull the
errorsarray out as a list withgetList()and print its size afterError count:. - Loop over the list and print every message prefixed by a dash and a space, keeping the order the server used.
Common mistakes
Expecting an exception on 400
Nothing is thrown when the server rejects the payload. If your code assumes a failure will stop the program, it carries on with a body that has no
dataobject. Check the status explicitly.Calling getList() on a success body
When the payload is valid there is no
errorskey, andgetList("errors")returnsnull. Callingsize()on that throws aNullPointerException, so guard the call if the same code handles both outcomes.Asserting on exact message text everywhere
Messages are written for people and change more often than field names. Checking the count with
hasSize(2)and the field withcontainsString("email")keeps the test useful after a copy edit.
In a real test suite
Negative tests like this one are where API suites earn their keep. A typical JUnit 5 class has one test per rule: blank name, missing email, malformed email, each asserting a 400 and the matching entry in the array.
Teams often add a parameterised test that feeds a table of bad payloads through the same request and checks the expected error for each row.
Related lessons
- Validate JSON InputThe passing request against the same endpoint, with
validtrue and adataobject. - Extract List of ValuesPractises
getList()on a successful/usersresponse. - hasItem and hasItemsUses
hasItem()andhasItems()to assert on values inside a JSON array.
To try one of these calls on any API endpoint without a task, open the Online Selenium Java Compiler (REST Assured is included).
Starter code
The editor above opens with this code. Fill in the TODO lines, then run and submit it.
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import io.restassured.http.ContentType;
import static io.restassured.RestAssured.*;
import java.util.List;
public class Main {
public static void main(String[] args) {
RestAssured.baseURI = "https://testkru.com/api";
// TODO: POST to /validate/json with body: {"name": ""}
// TODO: Print status code
// TODO: Print the "valid" field
// TODO: Get the "errors" list and print its size
// TODO: Loop through errors and print each with "- " prefix
}
}