Resource library

QA How-To

REST Assured: Extract Values from a Response with JsonPath

REST Assured extract response values: a hands-on JsonPath guide to nested fields, lists, filters, request chaining, null handling, and decimal precision.

22 min read | 3,230 words

TL;DR

Validate the response, then call .extract().path("id") for one field or response.jsonPath().getInt("id") for several. Use typed getters for arrays and nested fields, and check status, nullability, and numeric semantics before chaining the extracted value into another request.

Key Takeaways

  • Validate status and media type before reading a success-path JSON field.
  • Use extract().path for one value and a retained Response with JsonPath for several.
  • Use getList with a class argument for typed array projections.
  • REST Assured JsonPath uses Groovy GPath expressions rather than Jayway JSONPath syntax.
  • Keep extracted IDs within the test flow that uses them.
  • Handle missing fields, 204 responses, and decimal precision according to the API contract.

REST Assured extract response values with JsonPath when a test needs a field from one HTTP response for assertions or a later request. Capture a validated Response, call response.jsonPath().getInt("id") or another typed getter, and use the result only after checking status and shape. For a single field, .then().extract().path("id") is shorter. For several fields, reuse one JsonPath instance.

This tutorial builds a small Java API test suite around a local HTTP server. It covers scalar and nested fields, arrays, filtering, request chaining, missing values, and decimal precision. Every example uses the same fixture, so you can reproduce the expected values without relying on a public service or changing sample data. The REST Assured given, when, then tutorial explains the fluent request chain if that syntax is new to you.

What You Will Build

  • A Maven test project with REST Assured, JUnit Jupiter, and a local JSON fixture served by the JDK.
  • Tests that read one response value, several nested values, and a list of values without fetching the same endpoint repeatedly.
  • A filtered collection assertion that uses REST Assured's GPath expressions correctly.
  • A two-request flow that extracts an order ID and sends it in a shipment request.
  • Defensive checks for absent fields, HTTP 204, and money-like decimal values.

The fixture has GET /orders/42, GET /orders, GET /missing, GET /empty, and POST /shipments. The server binds to a free loopback port and stops after the class finishes. The examples therefore avoid credentials, network outages, and collisions with a service already running on a fixed port.

Prerequisites

Use JDK 17, Maven 3.9.11, REST Assured 6.0.1, JUnit Jupiter 5.13.4, Maven Compiler Plugin 3.14.1, and Maven Surefire Plugin 3.5.3 for the reproducible setup below. These are published versions, not guessed future pins. REST Assured 6 requires Java 17 or newer. If your team uses a different approved Maven or JUnit version, match the version already installed and confirm compatibility before changing the POM. See the REST Assured getting started guide, JUnit 5 release notes, and Maven 3.9.11 release notes.

Check the executables first:

java -version
mvn -version

The java command should report a 17 runtime, and mvn -version should report the intended Maven version and the same Java home. If Maven reports a different JDK, fix JAVA_HOME before debugging any test compilation error. You need network access once to download dependencies from your configured Maven repositories; the actual tests make only loopback requests. In a corporate build, keep the existing mirror and use its approved artifact versions rather than adding an unreviewed repository.

Step 1: Create the REST Assured extraction project

Make an empty directory, then write this complete pom.xml. The rest-assured artifact includes its JsonPath module, so you do not need a second explicit JsonPath dependency. Put REST Assured before JUnit as the project's setup guide recommends for Hamcrest dependency alignment.

mkdir -p rest-assured-extract/src/test/java/example
cd rest-assured-extract
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>example</groupId>
  <artifactId>rest-assured-extract</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <maven.compiler.release>17</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <version>6.0.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>5.13.4</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.14.1</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.5.3</version>
      </plugin>
    </plugins>
  </build>
</project>

Verify Step 1: Run mvn -q test. With no test class yet, Maven should complete successfully after resolving dependencies. If a repository mirror rejects one artifact, the failure will name the exact coordinate. Do not replace a failed download with an arbitrary version; check your mirror and the published artifact first. You can also run mvn -q dependency:tree if that plugin is available in your environment to inspect the resolved REST Assured modules.

Step 2: REST Assured Extract Response Values from One Request

Create src/test/java/example/ResponseExtractionTest.java with this complete class. The JDK's HttpServer provides deterministic JSON. @BeforeAll starts it once for the class and captures the actual port. @AfterAll closes it. The first test checks HTTP status and media type before extracting the order ID. Keep the server and helper methods in this file while adding the later tests inside the class, immediately before its final closing brace.

package example;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import io.restassured.path.json.JsonPath;
import io.restassured.path.json.config.JsonPathConfig;
import io.restassured.response.Response;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

import static io.restassured.RestAssured.given;
import static io.restassured.path.json.config.JsonPathConfig.NumberReturnType.BIG_DECIMAL;
import static org.junit.jupiter.api.Assertions.*;

class ResponseExtractionTest {
    private static HttpServer server;
    private static String baseUrl;

    @BeforeAll
    static void startServer() throws IOException {
        server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
        server.createContext("/orders/42", exchange -> send(exchange, 200,
            "{\"id\":42,\"status\":\"PAID\",\"customer\":{\"id\":7,\"name\":\"Ada\"}," +
            "\"total\":19.95,\"items\":[{\"sku\":\"A-1\",\"quantity\":2}," +
            "{\"sku\":\"B-2\",\"quantity\":1}],\"discount\":null}"));
        server.createContext("/orders", exchange -> send(exchange, 200,
            "{\"orders\":[{\"id\":42,\"status\":\"PAID\"}," +
            "{\"id\":43,\"status\":\"PENDING\"}],\"meta\":{\"count\":2}}"));
        server.createContext("/missing", exchange -> send(exchange, 404,
            "{\"error\":{\"code\":\"ORDER_NOT_FOUND\",\"message\":\"No order\"}}"));
        server.createContext("/empty", exchange -> {
            exchange.sendResponseHeaders(204, -1);
            exchange.close();
        });
        server.createContext("/shipments", exchange -> {
            String request = new String(exchange.getRequestBody().readAllBytes(),
                StandardCharsets.UTF_8);
            if ("POST".equals(exchange.getRequestMethod())
                && request.contains("\"orderId\":42")) {
                send(exchange, 201, "{\"shipmentId\":900,\"orderId\":42}");
            } else {
                send(exchange, 400, "{\"error\":{\"code\":\"BAD_SHIPMENT\"}}");
            }
        });
        server.start();
        baseUrl = "http://127.0.0.1:" + server.getAddress().getPort();
    }

    private static void send(HttpExchange exchange, int status, String json)
            throws IOException {
        byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
        exchange.getResponseHeaders().set("Content-Type", "application/json");
        exchange.sendResponseHeaders(status, bytes.length);
        try (var output = exchange.getResponseBody()) {
            output.write(bytes);
        }
    }

    @AfterAll
    static void stopServer() {
        server.stop(0);
    }

    @Test
    void extractsValidatedOrderId() {
        int id = given()
            .when().get(baseUrl + "/orders/42")
            .then().statusCode(200).contentType("application/json")
            .extract().path("id");
        assertEquals(42, id);
    }
}

Verify Step 2: Run mvn -q -Dtest=ResponseExtractionTest#extractsValidatedOrderId test. Expect one test and no failure. The important order is request, validation, extraction, then Java assertion. If the endpoint returns an error page instead of JSON in a real system, a status or content-type failure points to the protocol problem before a path lookup obscures it.

The path("id") call is convenient for a single value. It returns a generic result inferred from assignment, so choose a Java type that matches the JSON field. If you expect several values, take the validated Response and create one JsonPath reader. That makes the response available for headers and status as well as body fields. The REST Assured request and response spec guide shows how to reuse transport setup without hiding the business assertion.

Step 3: Extract nested fields with one JsonPath reader

Add the method below before the class's last }. It obtains a validated Response, then reads customer.id and customer.name from one JsonPath object. Dotted paths walk nested JSON objects. The getInt and getString names make the expected Java type visible in review.

@Test
void extractsNestedCustomerFields() {
    Response response = given()
        .when().get(baseUrl + "/orders/42")
        .then().statusCode(200).contentType("application/json")
        .extract().response();

    JsonPath json = response.jsonPath();
    int customerId = json.getInt("customer.id");
    String customerName = json.getString("customer.name");

    assertEquals(7, customerId);
    assertEquals("Ada", customerName);
    assertEquals(42, json.getInt("id"));
}

Verify Step 3: Run mvn -q -Dtest=ResponseExtractionTest#extractsNestedCustomerFields test. All three assertions should pass. A failing customer.name assertion usually means the service changed the field name, nesting, or capitalization. Inspect a sanitized response sample and update the contract deliberately, rather than suppressing the assertion with a default name.

Keep a distinction between an assertion and extraction. .then().body("customer.id", equalTo(7)) checks a fixed expected value; json.getInt("customer.id") makes the value available to Java code. Use both when the field has a known contract and is also needed later. Avoid making every field a Java variable merely to compare it with a literal. Direct body matchers often produce clearer mismatch output for simple fixed expectations. A saved Response becomes valuable when you need several values or need to inspect a response header beside the JSON body.

Step 4: Read arrays and object maps without unsafe casts

Add the next method. getList("items.sku", String.class) projects the sku property from each object in the items array. getList("items.quantity", Integer.class) does the same for quantities. For one object, getMap("customer") gives a map of its fields. Use the typed getter when the JSON contract fixes the element type; it avoids scattering raw Object casts through a test.

@Test
void extractsItemListsAndCustomerMap() {
    JsonPath json = given()
        .when().get(baseUrl + "/orders/42")
        .then().statusCode(200).contentType("application/json")
        .extract().response().jsonPath();

    List<String> skus = json.getList("items.sku", String.class);
    List<Integer> quantities = json.getList("items.quantity", Integer.class);
    Map<String, Object> customer = json.getMap("customer");

    assertEquals(List.of("A-1", "B-2"), skus);
    assertEquals(List.of(2, 1), quantities);
    assertEquals("Ada", customer.get("name"));
    assertEquals(7, customer.get("id"));
}

Verify Step 4: Run mvn -q -Dtest=ResponseExtractionTest#extractsItemListsAndCustomerMap test. The lists should preserve fixture order. If your production API does not promise order, compare as a set or assert by a stable key instead of copying this order-sensitive check. Also decide how an empty array differs from a missing items field in your contract. An empty collection can be a valid result, whereas a missing key may signal an incompatible response.

Need REST Assured call Result in this fixture Best use
One scalar after validation .extract().path("id") 42 One value for the next statement
Several body fields response.jsonPath() Reusable reader Related values from one response
Array projection getList("items.sku", String.class) ["A-1", "B-2"] Uniform list of leaf values
One object getMap("customer") ID and name map Small dynamic envelope
Whole body as text response.asString() Raw JSON Diagnostics or external parser

REST Assured's JsonPath uses Groovy GPath expressions, not Jayway JSONPath syntax. A token such as $..sku from another library is not a drop-in replacement for items.sku. The REST Assured usage documentation makes that distinction explicit. Keep queries simple enough that another engineer can map each segment back to the response body.

Step 5: Filter a collection and inspect response metadata

The GET /orders fixture has two orders. Add this method to select the paid order and cross-check the reported count. findAll { it.status == 'PAID' }.id is a GPath expression: it denotes each order, the predicate keeps matching objects, and .id projects their IDs. Because the API's list count is a separate field, the test checks it independently.

@Test
void filtersPaidOrdersAndChecksCount() {
    Response response = given()
        .when().get(baseUrl + "/orders")
        .then().statusCode(200).contentType("application/json")
        .extract().response();

    JsonPath json = response.jsonPath();
    List<Integer> paidIds =
        json.getList("orders.findAll { it.status == 'PAID' }.id", Integer.class);
    List<Integer> allIds = json.getList("orders.id", Integer.class);

    assertEquals(List.of(42), paidIds);
    assertEquals(List.of(42, 43), allIds);
    assertEquals(allIds.size(), json.getInt("meta.count"));
    assertTrue(response.getHeader("Content-Type").startsWith("application/json"));
}

Verify Step 5: Run mvn -q -Dtest=ResponseExtractionTest#filtersPaidOrdersAndChecksCount test. Expect the selected list to contain only 42. If it is empty, first check whether the API changed the status value or moved orders; do not assume the filter implementation is broken. If meta.count is a total across all pages rather than the current page size, this equality is the wrong production assertion. Document the service's pagination semantics before transferring this test to a real endpoint.

The header comes from Response.getHeader, not JsonPath. A JSON path sees only the body. Likewise, status is a response property, not a JSON field unless the API separately includes a status key. Keeping these scopes distinct prevents a misleading test that reads a business status while accidentally ignoring HTTP 500. For more contract-level checks, see the JSON schema validation guide.

Step 6: Chain an extracted ID into a second request

Add this two-call test. The first response supplies an order ID. The second call sends that ID in a JSON request body to POST /shipments. The fixture returns 201 only when it sees the expected ID; a wrong extraction therefore fails at the second HTTP status assertion. This models the common create-then-read or read-then-action workflow without a hard-coded global variable.

@Test
void usesExtractedOrderIdInShipmentRequest() {
    int orderId = given()
        .when().get(baseUrl + "/orders/42")
        .then().statusCode(200).contentType("application/json")
        .extract().path("id");

    Response shipment = given()
        .contentType("application/json")
        .body("{\"orderId\":" + orderId + "}")
        .when().post(baseUrl + "/shipments")
        .then().statusCode(201).contentType("application/json")
        .extract().response();

    assertEquals(900, shipment.jsonPath().getInt("shipmentId"));
    assertEquals(orderId, shipment.jsonPath().getInt("orderId"));
}

Verify Step 6: Run mvn -q -Dtest=ResponseExtractionTest#usesExtractedOrderIdInShipmentRequest test. The test should pass with a 201 response. Temporarily changing the extracted ID to 43 should make the fixture return 400, proving the second request depends on the captured value. Restore the method afterward. For real API data, prefer object serialization or a request DTO over string concatenation when the JSON body contains escaping, optional fields, or user-controlled text.

Capture identifiers inside the test or a test-scoped workflow object. A static lastOrderId field allows parallel tests to overwrite each other's state and makes cleanup ambiguous. Validate the source response before using its value: otherwise an error payload might yield a null ID, and the downstream 400 hides the original problem. The REST Assured POJO serialization tutorial covers structured bodies once the payload is larger than this single numeric field.

Step 7: Handle absent values and bodyless responses

A missing JSON key and a key whose value is explicitly null can both produce Java null through a simple get call. The fixture's discount is explicitly null, while unknownField is absent. This method shows the safe baseline: inspect the response contract and assert the returned value instead of unboxing it into an int or calling a method on it. It also checks an HTTP 204 response without trying to parse an empty body as JSON.

@Test
void handlesNullMissingAndNoContent() {
    Response order = given()
        .when().get(baseUrl + "/orders/42")
        .then().statusCode(200).contentType("application/json")
        .extract().response();

    JsonPath json = order.jsonPath();
    assertNull(json.get("discount"));
    assertNull(json.get("unknownField"));

    Response noContent = given()
        .when().get(baseUrl + "/empty")
        .then().statusCode(204)
        .extract().response();
    assertEquals("", noContent.asString());
}

Verify Step 7: Run mvn -q -Dtest=ResponseExtractionTest#handlesNullMissingAndNoContent test. The expected result is a pass with two null checks and one empty-body check. Do not add .contentType("application/json") to a 204 assertion unless the actual service contract explicitly promises that header. A bodyless response has nothing for JsonPath to parse; a parse exception in this case is caused by choosing the wrong extraction operation.

If distinguishing an absent key from an explicit null matters, inspect the parent object with getMap and call containsKey. For a nested nullable field, extract its known parent with getMap and call containsKey on that map. For a root-level field, deserialize the body with a JSON parser that preserves key presence. Do not silently substitute zero for a missing numeric field: zero might be a legitimate business value. For documented error responses such as GET /missing, validate 404 first, then extract error.code; do not run the success path against it.

Step 8: Preserve decimal meaning during extraction

JSON has one number syntax, but Java has several numeric representations. REST Assured's default JSON number handling can give floating values for decimal fields. For money-like values, configure JsonPath to return BigDecimal and compare with compareTo when numeric equality matters more than scale. Add this method using the imports already present in the class.

@Test
void extractsTotalAsBigDecimal() {
    Response response = given()
        .when().get(baseUrl + "/orders/42")
        .then().statusCode(200).contentType("application/json")
        .extract().response();

    JsonPath json = response.jsonPath().using(
        JsonPathConfig.jsonPathConfig().numberReturnType(BIG_DECIMAL));
    BigDecimal total = json.get("total");

    assertEquals(0, total.compareTo(new BigDecimal("19.95")));
}

Verify Step 8: Run mvn -q -Dtest=ResponseExtractionTest#extractsTotalAsBigDecimal test, then run mvn -q test to execute all seven methods together. The first command isolates numeric configuration; the second catches accidental braces, imports, or fixture edits made while following the steps. In a financial API, also check currency, rounding policy, and units. A precise parser does not fix an API that sends the wrong amount or represents cents and dollars inconsistently.

Avoid new BigDecimal(19.95); constructing from a binary floating literal can carry its approximation into the expected value. A string literal is exact for the decimal shown. Keep this configuration local unless every test agrees on numeric semantics. Changing global REST Assured configuration during parallel execution can affect unrelated assertions. If a field is an integer ID, use getInt and do not convert it to BigDecimal merely because another field is currency.

REST Assured Extract Response Values: Choose the Right Form

For one validated field, .extract().path("id") is compact and keeps validation in the same fluent chain. For multiple related fields, .extract().response() followed by one JsonPath reader makes repeated body reads obvious and preserves access to headers. For a fixed business expectation, a body matcher may be clearer than extraction: .body("status", equalTo("PAID")) says what the service must return. Extraction is especially useful when the value is unknown before the call but must be carried into the next request.

Do not confuse dynamic with unverified. A generated ID should still satisfy a shape rule such as positive integer, nonblank string, or UUID format before it is reused. For a response that returns Location, the header may be a better source for the next request than a body ID. Choose the source promised by the API contract, and assert that the two agree if both are guaranteed.

The table in Step 4 summarizes the operations used here. One more distinction matters for large payloads: a JsonPath query is convenient for focused fields, but repeatedly parsing a very large document or writing intricate GPath predicates can make tests hard to maintain. Deserialize to a typed object when many fields and invariants are involved. The REST Assured tutorial for beginners gives broader request and assertion coverage.

Troubleshooting

Problem: ClassCastException when assigning an extracted number -> Check the JSON value and the Java target type. An integer-looking ID can be read with getInt; a decimal should be handled with the configured numeric return type. Do not force a raw get result into a narrower type without evidence.

Problem: JsonPath returns null for a field visible in a sample -> Print or attach the actual sanitized response from the failing call, including status and content type. The sample may represent a different endpoint, API version, array position, or error response. Recheck path case: customer.id and Customer.Id are different keys.

Problem: A copied JSONPath expression with $.. fails -> REST Assured uses Groovy GPath, not Jayway JSONPath. Rewrite the expression using paths such as orders.id or orders.findAll { it.status == 'PAID' }.id. Keep the expression in a focused test so failures identify the contract change.

Problem: A test attempts to parse HTTP 204 -> Assert the 204 status and empty body instead of calling jsonPath(). Review whether an endpoint sometimes returns 200 JSON and sometimes 204; branch on the documented status before selecting an extraction operation.

Problem: A chained request receives 400 -> Confirm that the first response passed validation, the extracted ID has the expected type, and the second request uses the correct content type and field name. In this fixture, POST /shipments deliberately rejects an ID other than 42, which makes the dependency observable.

Problem: Local fixture test cannot bind a socket -> Check whether your runtime permits loopback listeners and whether another security tool blocks Java's JDK HTTP server. This class asks the operating system for an available port, so a fixed-port collision should not occur. If the environment forbids sockets entirely, run the example in a developer machine or CI runner that permits loopback HTTP.

Interview Questions and Answers

Q: When would you use extract().path instead of response.jsonPath()?

Use extract().path when one validated field is all the test needs. Retain the response and create JsonPath when several fields, headers, or status details matter. The choice should make the operation and failure point easy to review.

Q: Does REST Assured JsonPath use the same syntax as Jayway JsonPath?

No. REST Assured's implementation uses Groovy GPath expressions. A Jayway recursive-descent expression does not transfer unchanged; use REST Assured's documented paths and collection operations.

Q: Why assert status before extracting an ID?

An error response may have a different body shape or no body at all. Status and media-type checks establish that the success schema is applicable. The resulting failure then identifies the original protocol error rather than a secondary null value.

Q: How would you extract IDs from an array?

Use getList("orders.id", Integer.class) for a uniform list of integer IDs. Assert the expected collection semantics separately, including ordering only when the API guarantees it. For a filtered subset, use a readable findAll expression or deserialize to a typed model.

Q: How do you handle a JSON decimal in a money assertion?

Configure JsonPath's number return type to BIG_DECIMAL, extract to BigDecimal, and construct the expected value from a string. Also validate currency and unit conventions, because numeric parsing alone cannot prove financial correctness.

Q: What does get("missingField") prove when it returns null?

Only that the query yielded no non-null value. A key may be absent or explicitly null. If that difference is part of the contract, inspect the containing object or use a parser that exposes key presence.

Q: Why avoid sharing extracted IDs in static fields?

Concurrent tests can overwrite them, and later tests become dependent on order. Keep the ID within one test flow or an isolated fixture object. Create and clean up test data under that scope.

Common Mistakes

  • Parsing a response before asserting the status and expected representation.
  • Using Jayway JSONPath syntax in REST Assured's GPath implementation.
  • Converting a nullable field directly into a Java primitive.
  • Asserting array order when the endpoint promises only a set of results.
  • Mistaking a body status property for the HTTP response status.
  • Building expected decimal values from Java double literals.
  • Fetching the same endpoint multiple times just to read different fields.
  • Storing a dynamic ID in mutable global test state.
  • Treating a 204 response as if it contained JSON.
  • Copying a complex filter expression without checking the exact fixture shape.

Where To Go Next

Apply this pattern to one real endpoint: validate status and content type, extract the smallest value needed by the next operation, and assert the second response. The REST Assured OAuth2 authentication guide helps when the chained calls need different scopes. Use the REST Assured logging filters guide to capture sanitized failures, and the API testing roadmap to place extraction within a broader contract-testing practice. If you are preparing for a role that asks about response parsing, the REST Assured interview questions and answers provide scenario prompts.

Conclusion

To extract response values in REST Assured, validate the HTTP response first, then use .extract().path("field") for one value or response.jsonPath() for several. Match each getter to the JSON type, treat null and bodyless responses explicitly, and keep captured values local to the workflow that uses them.

The local suite gives you a repeatable starting point. Run mvn -q test, then replace one fixture endpoint with your application's documented contract. Keep the validation order and only change paths, expected values, and request data that the real API actually promises.

Interview Questions and Answers

Explain the difference between extract().path and response.jsonPath().

The fluent extract().path form is concise for one value after validation. Retaining a Response gives access to multiple body fields and response metadata. I choose based on how much of the same response the test needs.

How do you ensure an extracted ID is safe to reuse?

I assert the source HTTP status and media type, then check the ID's type and business shape before building the next request. The value stays test-scoped so concurrent scenarios cannot overwrite it.

How would you select only paid order IDs?

For a small response, I can use a GPath expression such as orders.findAll { it.status == 'PAID' }.id and read it as List<Integer>. If the filter becomes hard to read or the object has many rules, I deserialize and filter typed objects in Java.

What happens if a JSON key is missing?

A simple JsonPath get can return null, which also occurs for an explicit JSON null. I avoid unboxing that result and check key presence separately when the contract distinguishes those cases.

How do you test a 204 response?

I assert HTTP 204 and the documented empty-body behavior. I do not invoke JsonPath on a bodyless response or impose a JSON content-type assertion unless the endpoint contract requires that header.

What is the numeric risk when extracting money values?

Default floating representations can introduce binary approximation, and BigDecimal built from a double literal can preserve it. I configure BIG_DECIMAL, use string-based expected values, and verify units and currency.

Why might a copied JSONPath filter fail in REST Assured?

REST Assured uses Groovy GPath, while many online examples target Jayway JSONPath. I confirm the library and write the expression against an actual response fixture.

Frequently Asked Questions

How do I extract a value from a REST Assured response?

After asserting the response status and content type, call .then().extract().path("field") for a single value. If you need several fields, extract the Response and call response.jsonPath() once.

How do I extract a nested JSON field?

Use a dotted GPath expression such as response.jsonPath().getInt("customer.id"). Check the live response shape and exact key capitalization before changing the path.

How do I extract a list of IDs with REST Assured?

Call response.jsonPath().getList("orders.id", Integer.class) when orders is an array of objects with integer IDs. Assert ordering only if the API contract promises it.

Can I use an extracted ID in another REST Assured request?

Yes. Validate the first response, assign its ID to a test-local variable, and supply it as a path parameter or request body value in the next call. Assert the second response independently.

Why does a JsonPath query return null?

The field may be absent, explicitly null, or queried against a different response shape such as an error payload. Check status and a sanitized body sample before adding a fallback.

How should I extract a decimal price?

Configure JsonPath to return BIG_DECIMAL and assign the result to BigDecimal. Build expected values from strings, and verify the API's currency and unit rules.

Does REST Assured use Jayway JSONPath?

No. REST Assured's JsonPath uses Groovy GPath syntax. Paths and filters copied from Jayway examples may need rewriting.

Related Guides