Integrating APIs with Retrofit: A Step-by-Step Guide

Daniel Angel
6 min readApr 13, 2023

--

In modern programming, APIs are a fundamental part of creating applications and services. A JSON API is a popular way to expose web services that can be consumed by other applications. In this article, we will learn how to consume a JSON API in Java using Retrofit, an HTTP client library.

Retrofit is a widely used HTTP client library for Java that simplifies the process of consuming RESTful APIs. Here are some advantages and disadvantages of using Retrofit:

Advantages:

  1. Simple and easy-to-use API: Retrofit provides a simple and intuitive API for making HTTP requests and handling responses, which makes it easy for developers to consume RESTful APIs in their applications.
  2. Type-safe: Retrofit generates a type-safe API based on the interface definition, which provides compile-time safety and reduces the risk of runtime errors.
  3. Customizable: Retrofit allows you to customize the request and response processing, add interceptors, and handle errors in a flexible and extensible way.
  4. Integration with other libraries: Retrofit integrates well with other libraries and frameworks, such as Spring Boot and RxJava, which allows you to build complex and scalable applications.

Disadvantages:

  1. Limited support for non-HTTP protocols: Retrofit is designed primarily for consuming RESTful APIs over HTTP, which means it has limited support for other protocols, such as WebSockets or MQTT.
  2. Learning curve: Retrofit has a steep learning curve, especially for developers who are not familiar with the concepts of RESTful APIs or HTTP clients.
  3. Limited control over the request and response lifecycle: Retrofit abstracts away many of the low-level details of the HTTP protocol, which may limit the developer’s control over the request and response lifecycle.

Overall, Retrofit is a powerful and versatile HTTP client library that provides many benefits for consuming RESTful APIs in Java applications. However, it may not be the best choice for all use cases, and developers should carefully evaluate its advantages and disadvantages before choosing it for their projects.

Step 1: Add Dependencies

To use Retrofit in your Java project, you first need to add the necessary dependencies to your project’s build file (e.g. pom.xml if you are using Maven or build.gradle if you are using Gradle). Here are the dependencies you need to add:

Maven:

<dependencies>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>

Gradle:

dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
}

These dependencies will give you the core Retrofit library and the Gson converter, which is used to convert JSON responses into Java objects. You can replace Gson with other converters, depending on the format of the response you expect from the API.

Step 2: Create an Interface for the API

Once you have added the dependencies to your project, you can start creating an interface that defines the API endpoints. Each endpoint should be represented as a method in the interface, with annotations that specify the HTTP method, the endpoint URL, and any query parameters or request body.

Here’s an example interface for a simple API that returns a list of GitHub repositories for a given user:

import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;

public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repository>> listRepos(@Path("user") String user);
}

In this example, the @GET annotation specifies that this method makes an HTTP GET request, and the URL for the request is "users/{user}/repos", where {user} is a path parameter that will be replaced with the actual user name when the request is made. The @Path annotation specifies that the user parameter in the URL should be replaced with the value passed to the listRepos method.

The return type of the method is a Call object that represents the HTTP response. The Call object is asynchronous and allows you to perform the request in the background and receive a callback when the response is available. The generic type of the Call object specifies the type of the response body, which in this case is a list of Repository objects.

You can add more methods to this interface to define other API endpoints. Make sure to annotate each method with the appropriate HTTP method and URL.

Step 3: Create a Client Class for the API

After creating the interface for your API, you need to create a client class that uses Retrofit to make requests to the API. The client class should use the interface you created in the previous step to define the endpoints and make the actual HTTP requests.

Here’s an example client class for the GitHub API:

import java.io.IOException;
import java.util.List;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class GitHubClient {
private static final String BASE_URL = "https://api.github.com/";
private final GitHubService gitHubService;

public GitHubClient() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();

gitHubService = retrofit.create(GitHubService.class);
}

public List<Repository> listRepositories(String user) throws IOException {
Call<List<Repository>> call = gitHubService.listRepos(user);
Response<List<Repository>> response = call.execute();
return response.body();
}
}

Step 4: Define the Repository

Once you have created the client class for your API, you can define a repository class that encapsulates the logic for making API requests and processing the responses. The repository class should use the client class to make the actual API requests and return the data in a format that is convenient for the rest of your application.

Here’s an example repository class for the GitHub API:

import java.io.IOException;
import java.util.List;

public class GitHubRepository {
private final GitHubClient gitHubClient;

public GitHubRepository() {
gitHubClient = new GitHubClient();
}

public List<Repository> listRepositories(String user) throws IOException {
return gitHubClient.listRepositories(user);
}
}

In this example, the GitHubRepository class has a constructor that creates a new GitHubClient object. The listRepositories method takes a String argument user and calls the corresponding method on the GitHubClient object to make an HTTP GET request to the "users/{user}/repos" endpoint and retrieve a list of Repository objects.

You can add more methods to this repository class to encapsulate additional API requests and data processing logic.

Step 5: Make a Controller

Now that you have defined the repository class, you can create a controller class that exposes the repository methods as REST endpoints. The controller class should handle incoming HTTP requests, call the appropriate methods on the repository object to retrieve the data, and return the data as an HTTP response.

Here’s an example controller class for the GitHub API:

import java.io.IOException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class GitHubController {
private final GitHubRepository gitHubRepository;

@Autowired
public GitHubController(GitHubRepository gitHubRepository) {
this.gitHubRepository = gitHubRepository;
}

@GetMapping("/repos/{user}")
public List<Repository> listRepositories(@PathVariable String user) throws IOException {
return gitHubRepository.listRepositories(user);
}
}

In this example, the GitHubController class is annotated with @RestController and @RequestMapping("/api") to indicate that it handles REST requests and its base path is /api. The GitHubRepository object is autowired into the constructor.

The listRepositories method is annotated with @GetMapping("/repos/{user}") to indicate that it handles GET requests to the /api/repos/{user} endpoint. The @PathVariable annotation is used to extract the user parameter from the URL and pass it to the corresponding method on the GitHubRepository object. The method returns a list of Repository objects, which are automatically serialized to JSON by Spring Boot.

You can add more methods to this controller class to handle additional endpoints and data transformations.

Step 6: Test the API with cURL

After you have defined the controller class, you can test the API endpoints using cURL, a command-line tool for transferring data using various network protocols. cURL is useful for testing REST APIs because it allows you to send HTTP requests and view the responses in your terminal.

Here’s an example cURL command to test the /api/repos/{user} endpoint of the GitHub API:

curl http://localhost:8080/api/repos/octocat

In this example, the curl command sends a GET request to the /api/repos/octocat endpoint of the local server running on port 8080. The server should respond with a JSON array of repository objects owned by the octocat user.

You can use various options with the curl command to customize the request headers, request methods, and request bodies. For example, you can use the -H option to set a custom header, the -X option to specify a request method, and the -d option to send data in the request body.

After testing the API with cURL, you can integrate it with your front-end application or other services that consume REST APIs.

Conclusion

In conclusion, using Retrofit and Spring Boot, you can easily consume RESTful APIs in your Java applications. In this process, you can create a client class to handle the API requests, define a repository class to encapsulate the logic for making API requests and processing the responses, create a controller class to expose the repository methods as REST endpoints, and test the API with cURL.

This approach allows you to create a clean, modular, and scalable architecture for your applications that separates the concerns of data access, data processing, and API communication. By following these steps, you can efficiently consume and expose APIs in your Java applications, leading to faster development and better performance.

--

--

Daniel Angel
Daniel Angel

Written by Daniel Angel

Backend developer | Java, Spring boot, Cloud| Laravel, Php

No responses yet