Introduction

In our previous post, we explored POST Requests in REST Assured, learning how to create new resources. Now, we’ll dive into PUT Requests, which are used to update existing resources on the server. This guide is designed for beginners and experienced developers, providing clear explanations and practical examples to help you master PUT requests in REST Assured.

Key Point: PUT requests replace an existing resource with new data, making them ideal for updating records like user profiles or posts in a RESTful API.

What is a PUT Request?

A PUT Request is an HTTP method used to update an existing resource on the server by sending a complete representation of the resource in the request body. Unlike POST, which creates new resources, PUT replaces the entire resource identified by the URL. For example, sending a PUT request to /users/1 with a JSON payload updates the user with ID 1.

PUT requests are idempotent, meaning multiple identical requests produce the same result. In REST Assured, PUT requests are performed using the put() method, often combined with a request body and headers.

Performing PUT Requests in REST Assured

Let’s explore how to perform and validate PUT requests using REST Assured, using the public API https://jsonplaceholder.typicode.com for examples. Note that this API simulates updates without persisting changes, making it safe for practice.

Option 1: Basic PUT Request with JSON Body

The most common way to send a PUT request is with a JSON request body, defined as a string.


import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

public class BasicPutTest {

    @Test
    public void testBasicPut() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        String jsonBody = "{\"id\": 1, \"title\": \"Updated Post\", \"body\": \"This is an updated post\", \"userId\": 1}";

        given()
            .contentType("application/json")
            .body(jsonBody)
            .when()
                .put("/posts/1")
            .then()
                .statusCode(200)
                .body("title", equalTo("Updated Post"))
                .body("body", equalTo("This is an updated post"))
                .body("userId", equalTo(1));
    }
}

Explanation:

  • contentType("application/json"): Sets the Content-Type header to indicate a JSON payload.
  • body(jsonBody): Sends the JSON string as the request body, including the resource’s full representation.
  • put("/posts/1"): Sends a PUT request to update the post with ID 1.
  • then(): Validates the response:
    • statusCode(200): Ensures the update was successful (200 OK).
    • body("title", equalTo("Updated Post")): Verifies the updated title.
    • body("body", equalTo("This is an updated post")): Confirms the updated body.
    • body("userId", equalTo(1)): Checks the user ID.
Important: Include all required fields in the request body, as PUT replaces the entire resource. Missing fields may be set to null or default values by the server.

Option 2: PUT Request with Java Object

For cleaner code, use a Java object as the request body. REST Assured serializes the object to JSON using a library like Jackson.

Ensure the Jackson dependency is in your pom.xml:



    com.fasterxml.jackson.core
    jackson-databind
    2.15.2
    test

Create a Java class and use it in a PUT request:


import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

// Java class for the request body
class Post {
    private int id;
    private String title;
    private String body;
    private int userId;

    public Post(int id, String title, String body, int userId) {
        this.id = id;
        this.title = title;
        this.body = body;
        this.userId = userId;
    }

    // Getters and setters
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public String getBody() { return body; }
    public void setBody(String body) { this.body = body; }
    public int getUserId() { return userId; }
    public void setUserId(int userId) { this.userId = userId; }
}

public class PutObjectTest {

    @Test
    public void testPutWithObject() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        Post post = new Post(1, "Updated Post", "This is an updated post", 1);

        given()
            .contentType("application/json")
            .body(post)
            .when()
                .put("/posts/1")
            .then()
                .statusCode(200)
                .body("title", equalTo("Updated Post"))
                .body("userId", equalTo(1));
    }
}

Explanation:

  • Post: A Java class representing the JSON structure.Key Point: Java objects are preferred for request bodies in REST Assured because they are less error-prone and more maintainable than JSON strings.

    Option 3: PUT Request with Request Specification

    Use a Request Specification to reuse common settings like headers or base URI for PUT requests.

    
    import io.restassured.RestAssured;
    import io.restassured.builder.RequestSpecBuilder;
    import io.restassured.specification.RequestSpecification;
    import org.junit.jupiter.api.BeforeAll;
    import org.junit.jupiter.api.Test;
    import static io.restassured.RestAssured.*;
    import static org.hamcrest.Matchers.*;
    
    public class PutWithSpecTest {
    
        private static RequestSpecification requestSpec;
    
        @BeforeAll
        public static void setup() {
            requestSpec = new RequestSpecBuilder()
                .setBaseUri("https://jsonplaceholder.typicode.com")
                .setContentType("application/json")
                .build();
        }
    
        @Test
        public void testPutWithSpec() {
            String jsonBody = "{\"id\": 1, \"title\": \"Updated Post\", \"body\": \"This is an updated post\", \"userId\": 1}";
    
            given()
                .spec(requestSpec)
                .body(jsonBody)
                .when()
                    .put("/posts/1")
                .then()
                    .statusCode(200)
                    .body("title", equalTo("Updated Post"));
        }
    }
    

    Explanation:

    • RequestSpecBuilder: Defines a reusable specification with the base URI and content type.
    • spec(requestSpec): Applies the specification to the test, reducing code duplication.
    Pro Tip: Use Request Specifications for common settings in PUT requests to streamline test code and ensure consistency.

    Step 1: Combining PUT with Path Parameters

    PUT requests often use path parameters to specify the resource to update.

    
    import io.restassured.RestAssured;
    import org.junit.jupiter.api.Test;
    import static io.restassured.RestAssured.*;
    import static org.hamcrest.Matchers.*;
    
    public class PutWithPathParamTest {
    
        @Test
        public void testPutWithPathParam() {
            RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
    
            String jsonBody = "{\"id\": 2, \"title\": \"Updated Post\", \"body\": \"Updated content\", \"userId\": 1}";
    
            given()
                .contentType("application/json")
                .pathParam("postId", 2)
                .body(jsonBody)
                .when()
                    .put("/posts/{postId}")
                .then()
                    .statusCode(200)
                    .body("id", equalTo(2))
                    .body("title", equalTo("Updated Post"));
        }
    }
    

    Explanation:

    • pathParam("postId", 2): Specifies the post ID in the URL (/posts/2).
    • The JSON body includes the id field to match the resource being updated.

    Step 2: Extracting Response Data

    Extract the response from a PUT request for further validation or processing.

    
    import io.restassured.RestAssured;
    import io.restassured.response.Response;
    import org.junit.jupiter.api.Test;
    import static io.restassured.RestAssured.*;
    
    public class PutExtractResponseTest {
    
        @Test
        public void testExtractPutResponse() {
            RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
    
            String jsonBody = "{\"id\": 1, \"title\": \"Updated Post\", \"body\": \"This is an updated post\", \"userId\": 1}";
    
            Response response = given()
                .contentType("application/json")
                .body(jsonBody)
                .when()
                    .put("/posts/1")
                .then()
                    .statusCode(200)
                    .extract().response();
    
            String title = response.path("title");
            System.out.println("Updated Post Title: " + title);
    
            // Additional validation
            assert title.equals("Updated Post");
        }
    }
    

    Explanation:

    • extract().response(): Extracts the full response.
    • response.path("title"): Retrieves the title field for validation.

    Step 3: Verify Setup with pom.xml

    Ensure your pom.xml includes dependencies for REST Assured, JUnit, and Jackson:

    
    
        
            io.rest-assured
            rest-assured
            5.4.0
            test
        
        
            org.junit.jupiter
            junit-jupiter
            5.10.2
            test
        
        
            org.hamcrest
            hamcrest
            2.2
            test
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.15.2
            test
        
    
    

    Run the tests using mvn test or your IDE’s test runner to confirm the setup.

    Tips for Beginners

    • Include All Fields: Ensure the request body contains all required fields for the resource, as PUT replaces the entire resource.
    • Use Java Objects: Prefer Java objects for request bodies to improve code readability and reduce errors.
    • Check API Docs: Verify the expected status code (typically 200 or 204) and required fields in the API documentation.
    • Enable Logging: Use RestAssured.enableLoggingOfRequestAndResponseIfValidationFails() to debug issues.
    Troubleshooting Tip: If a PUT request returns a 400 Bad Request or 404 Not Found error, check the request body, Content-Type header, and URL. Ensure the resource ID exists and the body is correctly formatted.

    What’s Next?

    In the next post, we’ll cover PATCH Requests, exploring how to partially update resources using REST Assured. Stay tuned for more hands-on examples!

    ๅผ„ System:

    PATCH Requests in REST Assured: Partially Updating Resources with APIs

    Introduction

    In our previous post, we explored PUT Requests in REST Assured, learning how to update entire resources. Now, we’ll dive into PATCH Requests, which allow partial updates to existing resources. This guide is designed for beginners and experienced developers, providing clear explanations and practical examples to master PATCH requests in REST Assured.

    Key Point: PATCH requests update specific fields of an existing resource without replacing the entire resource, offering a more targeted approach than PUT.

    What is a PATCH Request?

    A PATCH Request is an HTTP method used to make partial updates to an existing resource on the server. Unlike PUT, which replaces the entire resource, PATCH modifies only the specified fields, leaving others unchanged. For example, a PATCH request to /users/1 might update just the user's email address without affecting other fields like name or password.

    PATCH is particularly useful for updating specific attributes of a resource efficiently. In REST Assured, PATCH requests are performed using the patch() method, typically with a request body containing the fields to update.

    Performing PATCH Requests in REST Assured

    Let’s explore how to perform and validate PATCH requests using REST Assured, using the public API https://jsonplaceholder.typicode.com for examples. Note that this API simulates updates without persisting changes, making it ideal for practice.

    Option 1: Basic PATCH Request with JSON Body

    The simplest way to send a PATCH request is with a JSON request body containing only the fields to update.

    
    import io.restassured.RestAssured;
    import org.junit.jupiter.api.Test;
    import static io.restassured.RestAssured.*;
    import static org.hamcrest.Matchers.*;
    
    public class BasicPatchTest {
    
        @Test
        public void testBasicPatch() {
            RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
    
            String jsonBody = "{\"title\": \"Patched Post\"}";
    
            given()
                .contentType("application/json")
                .body(jsonBody)
                .when()
                    .patch("/posts/1")
                .then()
                    .statusCode(200)
                    .body("title", equalTo("Patched Post"))
                    .body("body", notNullValue()); // Ensure other fields remain unchanged
        }
    }
    

    Explanation:

    • contentType("application/json"): Sets the Content-Type header to indicate a JSON payload.
    • body(jsonBody): Sends a JSON body with only the title field to update.
    • patch("/posts/1"): Sends a PATCH request to update the post with ID 1.
    • then(): Validates the response:
      • statusCode(200): Ensures the update was successful.
      • body("title", equalTo("Patched Post")): Verifies the updated title.
      • body("body", notNullValue()): Confirms other fields like body remain unchanged.
    Important: Unlike PUT, PATCH only updates the fields specified in the request body. Ensure the API supports partial updates, as some APIs may treat PATCH like PUT.

    Option 2: PATCH Request with Java Object

    Use a Java object for the request body to make the code cleaner and less error-prone. REST Assured serializes the object to JSON using a library like Jackson.

    Ensure the Jackson dependency is in your pom.xml:

    
    
        com.fasterxml.jackson.core
        jackson-databind
        2.15.2
        test
    
    

    Create a Java class for the partial update and use it in a PATCH request:

    
    import io.restassured.RestAssured;
    import org.junit.jupiter.api.Test;
    import static io.restassured.RestAssured.*;
    import static org.hamcrest.Matchers.*;
    
    // Java class for the request body
    class PostUpdate {
        private String title;
    
        public PostUpdate(String title) {
            this.title = title;
        }
    
        // Getter and setter
        public String getTitle() { return title; }
        public void setTitle(String title) { this.title = title; }
    }
    
    public class PatchObjectTest {
    
        @Test
        public void testPatchWithObject() {
            RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
    
            PostUpdate update = new PostUpdate("Patched Post");
    
            given()
                .contentType("application/json")
                .body(update)
                .when()
                    .patch("/posts/1")
                .then()
                    .statusCode(200)
                    .body("title", equalTo("Patched Post"))
                    .body("userId", notNullValue());
        }
    }
    

    Explanation:

    • PostUpdate: A Java class containing only the field to update (title).
    • body(update): Serializes the object to JSON, updating only the specified field.
    • This approach is cleaner and reduces errors compared to JSON strings.

    Option 3: PATCH Request with Request Specification

    Use a Request Specification to reuse common settings for PATCH requests.

    
    import io.restassured.builder.RequestSpecBuilder;
    import io.restassured.specification.RequestSpecification;
    import org.junit.jupiter.api.BeforeAll;
    import org.junit.jupiter.api.Test;
    import static io.restassured.RestAssured.*;
    import static org.hamcrest.Matchers.*;
    
    public class PatchWithSpecTest {
    
        private static RequestSpecification requestSpec;
    
        @BeforeAll
        public static void setup() {
            requestSpec = new RequestSpecBuilder()
                .setBaseUri("https://jsonplaceholder.typicode.com")
                .setContentType("application/json")
                .build();
        }
    
        @Test
        public void testPatchWithSpec() {
            String jsonBody = "{\"title\": \"Patched Post\"}";
    
            given()
                .spec(requestSpec)
                .body(jsonBody)
                .when()
                    .patch("/posts/1")
                .then()
                    .statusCode(200)
                    .body("title", equalTo("Patched Post"));
        }
    }
    

    Explanation:

    • RequestSpecBuilder: Defines a reusable specification with the base URI and content type.
    • spec(requestSpec): Applies the specification to the test.
    Pro Tip: Request Specifications streamline PATCH requests by centralizing common settings, making tests more maintainable.

    Step 1: Combining PATCH with Path Parameters

    PATCH requests often use path parameters to identify the resource to update.

    
    import io.restassured.RestAssured;
    import org.junit.jupiter.api.Test;
    import static io.restassured.RestAssured.*;
    import static org.hamcrest.Matchers.*;
    
    public class PatchWithPathParamTest {
    
        @Test
        public void testPatchWithPathParam() {
            RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
    
            String jsonBody = "{\"title\": \"Patched Post\", \"body\": \"Updated content\"}";
    
            given()
                .contentType("application/json")
                .pathParam("postId", 1)
                .body(jsonBody)
                .when()
                    .patch("/posts/{postId}")
                .then()
                    .statusCode(200)
                    .body("title", equalTo("Patched Post"))
                    .body("body", equalTo("Updated content"));
        }
    }
    

    Explanation:

    • pathParam("postId", 1): Specifies the post ID in the URL (/posts/1).
    • The JSON body updates only the specified fields (title and body).

    Step 2: Extracting Response Data

    Extract the response from a PATCH request for further validation or processing.

    
    import io.restassured.RestAssured;
    import io.restassured.response.Response;
    import org.junit.jupiter.api.Test;
    import static io.restassured.RestAssured.*;
    
    public class PatchExtractResponseTest {
    
        @Test
        public void testExtractPatchResponse() {
            RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
    
            String jsonBody = "{\"title\": \"Patched Post\"}";
    
            Response response = given()
                .contentType("application/json")
                .body(jsonBody)
                .when()
                    .patch("/posts/1")
                .then()
                    .statusCode(200)
                    .extract().response();
    
            String title = response.path("title");
            System.out.println("Updated Post Title: " + title);
    
            // Additional validation
            assert title.equals("Patched Post");
        }
    }
    

    Explanation:

    • extract().response(): Extracts the full response.
    • response.path("title"): Retrieves the title field for validation.

    Step 3: Verify Setup with pom.xml

    Ensure your pom.xml includes dependencies for REST Assured, JUnit, and Jackson:

    
    
        
            io.rest-assured
            rest-assured
            5.4.0
            test
        
        
            org.junit.jupiter
            junit-jupiter
            5.10.2
            test
        
        
            org.hamcrest
            hamcrest
            2.2
            test
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.15.2
            test
        
    
    

    Run the tests using mvn test or your IDE’s test runner to confirm the setup.

    Tips for Beginners

    • Understand API Behavior: Some APIs may not support PATCH or treat it like PUT. Check the API documentation.
    • Use Minimal Payloads: Include only the fields you want to update in the request body.
    • Validate Responses: Always check the response to ensure only the intended fields were updated.
    • Enable Logging: Use RestAssured.enableLoggingOfRequestAndResponseIfValidationFails() to debug issues.
    Troubleshooting Tip: If a PATCH request fails with a 400 Bad Request or 405 Method Not Allowed error, verify the API supports PATCH and the request body format is correct.

    What’s Next?

    In the next post, we’ll cover DELETE Requests, exploring how to delete resources using REST Assured. Stay tuned for more hands-on examples!