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:
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.
DSL: REST Assured provides a Domain Specific Language (DSL) for writing tests, which simplifies the process of writing complex HTTP requests.
Specification: It allows you to define detailed specifications for the API, which can be used to generate detailed reports and documentation.
Schema Validation: REST Assured supports schema validation for both JSON and XML, ensuring that the API responses match the expected structure.
Ease of Use: REST Assured is designed to be simple and intuitive, making it easy for beginners to get started with API testing.
Integration: It integrates seamlessly with existing Java-based testing ecosystems, including JUnit and TestNG.
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.
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.
Detailed Logging: REST Assured provides detailed logging capabilities, which can be very helpful for debugging and understanding the flow of requests and responses.
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/Tool | HttpURLConnection | HttpClient | Apache HttpClient | Spring RestTemplate | Spring WebClient | REST Assured |
HTTP/2 Support | No | Yes | Yes | No | Yes | Yes |
Non-Blocking I/O | No | Yes | Yes | No | Yes | No |
WebSocket Support | No | Yes | No | No | Yes | No |
OAuth2 Support | No | No | Yes | Yes | Yes | Yes |
JSON Support | No | No | No | Yes | Yes | Yes |
XML Support | No | No | No | Yes | Yes | Yes |
Fluent API | No | Yes | Yes | Yes | Yes | Yes |
Built-in Response Validation | No | No | No | No | No | Yes |
BDD Style Support | No | No | No | No | No | Yes |
Part of Java Standard Library | Yes | Yes | No | No | No | No |
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!
Subscribe to my newsletter
Read articles from Rakesh Vardan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Rakesh Vardan
Rakesh Vardan
I am a Software Development Engineer in Test (SDET) specializing in CI/CD processes, with a strong background in UI and API test automation. My expertise lies in designing robust testing frameworks that integrate seamlessly with CI/CD workflows, guaranteeing software quality and reliability.