Choosing the Optimal Approach for API Automation

A Simple Comparison of REST Assured, Java's Native HTTP Clients, and Spring Libraries

Choosing the Optimal Approach for API Automation

Introduction

As an automation engineer, testing APIs is a significant part of our role. While there are numerous tools available for this purpose, choosing the right one can significantly impact our testing efficiency. In this blog post, we'll explore several options, including native clients like HttpClient and HttpURLConnection, as well as REST Assured, Spring RestTemplate, Spring WebClient, and Apache HttpClient.

Let's explore a simple use case and add tests using all the options we have.

Consider our API URL https://jsonplaceholder.typicode.com/users/1 which returns the below JSON response.

So the test is to:

  • Invoke the GET API using any client

  • Get the response & validate status code is 200

  • Validate some parts of the response, maybe name

Let's see how we can accomplish this with different approaches.

The complete code for this tutorial with all examples discussed can be found on GitHub.

1. HttpURLConnection

HttpURLConnection has been a part of the Java standard library since Java 1.1. It's a blocking API, meaning it will hold the thread until it gets the response. It only supports HTTP/1.1. Its API is also low-level, which means we would need to write more code to do the same tasks as with other options.

    @Test
    void testWithHttpURLConnection() throws IOException {
        // prepare request
        URL url = new URL(this.URL);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");

        // send request
        connection.connect();

        // validate response
        assertEquals(200, connection.getResponseCode());
        assertEquals("application/json; charset=utf-8", connection
                .getHeaderField("Content-Type"));

        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String line;
        StringBuilder response = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            response.append(line);
        }
        reader.close();

        assertTrue(response.toString().contains("Leanne Graham"));
        connection.disconnect();
    }

This JUnit test uses Java's native HttpURLConnection to send a GET request to the given URL and validates the response. It first creates a new URL object and opens a connection to it using HttpURLConnection. The request method is set to GET. Then, it sends the request by calling connect(). It validates the response by checking that the response code is 200, indicating success and that the Content-Type header is application/json; charset=utf-8. It then reads the response body using a BufferedReader and checks that the response body contains the string "Leanne Graham". If any of these checks fail, the test will fail. If all checks pass, the test will pass. The test may throw an IOException if there's a problem sending the request or receiving the response. After all operations, it disconnects the connection by calling disconnect().

2. HttpClient

Introduced in Java 11, HttpClient is a modern and flexible API that supports both HTTP/1.1 and HTTP/2. It provides both synchronous (blocking) and asynchronous (non-blocking) programming models. However, it's more of a low level and doesn't provide the same level of functionality for testing as some other options.

    @Test
    void testWithHttpClient() throws IOException, InterruptedException {
        // prepare request
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(this.URL))
                .build();

        // send request
        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        // validate response
        assertEquals(200, response.statusCode());
        assertEquals("application/json; charset=utf-8", response.headers()
                .firstValue("Content-Type").get());
        assertTrue(response.body().contains("Leanne Graham"));
    }

This test uses Java's native HttpClient to send a GET request to a specified URL and validates the response. It first creates a new HttpClient instance and builds an HttpRequest for the specified URL. Then, it sends the HttpRequest using the HttpClient and receives the HttpResponse, specifying that the response body should be treated as a String. Then it validates the response as per our test scenario.

3. Apache HttpClient

Apache HttpClient is a robust, feature-rich, and flexible library that provides almost all the functionality needed to send HTTP requests and handle HTTP responses. It supports both blocking and non-blocking I/O models and provides full control over the HTTP protocol's details.

Make sure you're adding the appropriate Maven/Gradle dependency for Apache HttpClient in your project. For Maven, you can use:

    <dependency>
      <groupId>org.apache.httpcomponents.client5</groupId>
      <artifactId>httpclient5</artifactId>
      <version>5.3.1</version>
    </dependency>
    @Test
    void testWithApacheHttpClient() throws ProtocolException, IOException {
        // prepare request
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet request = new HttpGet(this.URL);

        // send request
        CloseableHttpResponse response = httpClient.execute(request);

        // validate response
        assertEquals(200, response.getCode());
        assertEquals("application/json; charset=utf-8",
                response.getHeader("Content-Type").getValue());
        assertTrue(EntityUtils.toString(response.getEntity())
                .contains("Leanne Graham"));
        httpClient.close();
    }

This test uses Apache's CloseableHttpClient to send a GET request to a specified URL and validates the response. It first creates a new CloseableHttpClient and builds a HttpGet request for the specified URL. Then, it sends the HttpGet request using the CloseableHttpClient and receives the CloseableHttpResponse. It validates the response similar to the previous examples. After all operations, it closes httpClient to free up system resources.

4. Spring RestTemplate

RestTemplate is a synchronous HTTP client that was part of the Spring Framework. It provides a higher-level, more user-friendly API compared to HttpClient and HttpURLConnection. However, as of Spring 5, RestTemplate is in maintenance mode, and it's suggested to use the non-blocking WebClient instead.

Make sure you're adding the appropriate Maven/Gradle dependency for Spring Web in your project. For Maven, you can use:

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>6.1.6</version>
    </dependency>
    @Test
    void testWithSpringRestTemplate() {
        // prepare and send request
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.getForEntity(this.URL, String.class);

        // validate response
        assertEquals(200, response.getStatusCodeValue());
        assertEquals("application/json; charset=utf-8", response.getHeaders()
                .getFirst("Content-Type"));
        assertTrue(response.getBody().contains("Leanne Graham"));
    }

This test uses Spring's RestTemplate to send a GET request to a specified URL and validates the response. It first creates a new RestTemplate and sends a GET request to the specified URL, receiving the response as a ResponseEntity<String>. Then it validates the response as per our test scenario.

5. Spring WebClient

WebClient is a non-blocking, reactive web client introduced in Spring 5 as part of the WebFlux module. It's designed to work in a non-blocking way and is suitable for use in reactive applications where traditional blocking I/O operations are inefficient.

Make sure you're adding the appropriate Maven/Gradle dependency for Spring Webflux in your project. For Maven, you can use:

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webflux</artifactId>
      <version>6.1.6</version>
    </dependency>
    @Test
    void testWithSpringWebClient() {
        // prepare and send request
        WebClient webClient = WebClient.create();
        ClientResponse response = webClient.get()
                .uri(this.URL)
                .exchange()
                .block();

        // validate response
        assert response != null;
        assertEquals(HttpStatus.OK, response.statusCode());
        assertEquals("application/json;charset=utf-8",
                Objects.requireNonNull(response.headers().asHttpHeaders().getContentType())
                        .toString());
        assertTrue(Objects.requireNonNull(response.bodyToMono(String.class).block())
                .contains("Leanne Graham"));
    }

This test uses Spring's WebClient to send a GET request to a specified URL and retrieve the response. It creates an instance of WebClient, sends the request, and blocks until the response is received. It validates the response similar to the previous examples. The Objects.requireNonNull() calls are used to ensure that the getContentType() and bodyToMono(String.class).block() methods do not return null. If they do, a NullPointerException will be thrown.

6. REST Assured

REST Assured is an open-source Java library that simplifies the testing and validation of REST APIs. It provides a high-level, fluent API for sending HTTP requests and validating responses, making it an ideal tool for testing in a behavior-driven development (BDD) style. It is built on top of Apache HTTP Client for handling HTTP requests and responses and Groovy for its syntax and language features. It also uses other libraries such as GSON and Jackson for JSON, and JAXB for XML.

Make sure you're adding the appropriate Maven/Gradle dependency for REST Assured in your project. For Maven, you can use:

    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <version>5.4.0</version>
      <scope>test</scope>
    </dependency>
    @Test
    void testWithRESTAssured() {
        given().
                baseUri(this.URL).       // prepare request
        when()
                .get().                  // send request
        then()
                .statusCode(200).and()   // validate response
                .body(containsString("Leanne Graham")).and()
                .header("Content-Type", "application/json; charset=utf-8");
    }

This test uses REST Assured to send a GET request to a specified URL and validate the response. The baseUri(this.URL) method sets the base URL for the request. The get() method sends the GET request. The statusCode(200) assertion checks that the status code of the response is 200, indicating success. The and() methods are used for readability and do not affect the execution of the test.

As we see with our examples, writing API tests & adding assertions with REST Assured is very easy. It stands out for its ease of use, powerful validation features, support for various types of authentication, and flexibility. It's built on top of the Apache HttpClient, which means we can customize it to suit our needs. We can add filters, define the request and response specifications, and more. Using REST Assured, we can write efficient tests with very few lines of readable code.

REST Assured offers several benefits for testing RESTful APIs:

  1. BDD Format: REST Assured supports Behavior Driven Development (BDD) format, making it easier to write, read, and understand tests. This also facilitates communication between developers, testers, and non-technical stakeholders.

  2. DSL: REST Assured provides a Domain Specific Language (DSL) for writing tests, which simplifies the process of writing complex HTTP requests.

  3. Specification: It allows you to define detailed specifications for the API, which can be used to generate detailed reports and documentation.

  4. Schema Validation: REST Assured supports schema validation for both JSON and XML, ensuring that the API responses match the expected structure.

  5. Ease of Use: REST Assured is designed to be simple and intuitive, making it easy for beginners to get started with API testing.

  6. Integration: It integrates seamlessly with existing Java-based testing ecosystems, including JUnit and TestNG.

  7. Flexibility: REST Assured supports a variety of HTTP methods, including GET, POST, PUT, DELETE, OPTIONS, PATCH, and HEAD, and can handle any type of MIME type, providing flexibility in testing different types of APIs.

  8. Authentication Support: REST Assured supports various types of authentication, such as Basic, Digest, Form, and OAuth, making it easier to test APIs that require user authentication.

  9. Detailed Logging: REST Assured provides detailed logging capabilities, which can be very helpful for debugging and understanding the flow of requests and responses.

  10. Built-in Support for Hamcrest Matchers: REST Assured includes built-in support for Hamcrest matchers, which allows for more readable and flexible assertions. This enhances the descriptiveness of our tests, making them easier to read and maintain.

Overall, REST Assured provides a comprehensive and user-friendly framework for testing RESTful APIs, making it a popular choice among developers and testers.

Here's a comparison table for all the mentioned solutions:

Feature/ToolHttpURLConnectionHttpClientApache HttpClientSpring RestTemplateSpring WebClientREST Assured
HTTP/2 SupportNoYesYesNoYesYes
Non-Blocking I/ONoYesYesNoYesNo
WebSocket SupportNoYesNoNoYesNo
OAuth2 SupportNoNoYesYesYesYes
JSON SupportNoNoNoYesYesYes
XML SupportNoNoNoYesYesYes
Fluent APINoYesYesYesYesYes
Built-in Response ValidationNoNoNoNoNoYes
BDD Style SupportNoNoNoNoNoYes
Part of Java Standard LibraryYesYesNoNoNoNo

Conclusion

While native clients like HttpClient and HttpURLConnection, as well as libraries like Spring RestTemplate, Spring WebClient, and Apache HttpClient have their specific uses, REST Assured is a superior choice for test automation engineers looking to efficiently test REST APIs. Its high-level, fluent API, powerful validation features, and support for various types of authentication make it a versatile and efficient tool for API test automation. So, if you're an automation engineer looking to streamline your API testing, give REST Assured a try!

Did you find this article valuable?

Support Rakesh Vardan by becoming a sponsor. Any amount is appreciated!