Retrofit Tutorial

What is Retrofit?

Retrofit is a type-safe, REST client for Java and Android application development. Retrofit is a library, which has interfaces, classes, and methods to serve the necessary functionality. The retrofit library can be used to parse JSON or XML data into POJOs (Plain Old Java Objects). Retrofit is open-source and developed by Square, Inc.

Where to get Retrofit?

There are many ways to get Retrofit.
  1. Way-One: Download and add the jar file in your project.
Official link for latest v2.5.0 .jar file: https://square.github.io/retrofit/
  1. Way-Two: Add Maven dependency to your project.
Get its dependency from Maven central repository or copy below code:
<dependency>

            <groupId>com.squareup.retrofit2</groupId>

            <artifactId>retrofit</artifactId>

            <version>2.5.0</version>

</dependency>
  1. Way-Three:For Gradle build projects, use this:
implementation ‘com.squareup.retrofit2:retrofit:2.5.0’

Retrofit implementation

Let’s learn it with a small example:
//retrofit turns HTTP API into a Java interface

Public interface RetroService {

            @GET(“users/{user}/records”)

            Call<List<Records>> listRecords(@Path(“user”) String user);

}

//retrofit class generates an implementation of the RetroService interface

Retrofit retrofit = new Retrofit.Builder().baseUrl(“https://api.javatpoint.com/”).build();

RetroService retroService = retrofit.create(RetroService.class);

//each call from the created RetroService can make a synchronous or asynchronous

//HTTP request to the remote webserver.

Call<List<Records>> records = retroService.listRecords(“python”);

Exploring Retrofit 2.3.0 API

Retrofit 2.3.0 API has two packages. You can find here some brief introduction about these packages: Package -- retrofit2 -- > This package has some interfaces and classes that help in turning REST API into a Java interface. Package -- retrofit2.http-- > This package has Annotations for interface methods to control the HTTP request behavior. Now, we will explore more:
 ---- retrofit2----
Interface name Usage
Call<T> It is used to invoke the retrofit method that sends a request to a web server and returns a response
CallAdapter<R, T> It is used to Modify a Call with response type R into the type T
Callback<T> It is used to communicate responses from a server or offline requests
Converter<F, T> It is used to convert objects to and from their representation in HTTP
Class name Usage
CallAdapter.Factory It creates CallAdapter instances based on the return type of the service interface methods
Converter.Factory It creates Converter instances based on a type and target usage
Response<T> It contains methods used for HTTP response queries
Retrofit It modifies a Java interface to HTTP calls by using annotations on the declared methods to define how requests are made
Retrofit.Builder It is used to build a new Retrofit object
HttpException It defines exceptions for an unexpected, non-2xx HTTP response
--retrofit2.http--
Annotation name Usage
Body Used on a service method param when there is need to directly control the request body of a POST/PUT request (instead of sending in as request parameters or form-style request body)
DELETE It makes a DELETE request
Field Named pair for a form-encoded request
FieldMap Named key/value pairs for a form-encoded request
FormUrlEncoded Denotes that the request body will use form URL encoding
GET Make a GET request
HEAD Make a HEAD request
Header Replaces the header with the value of its target
HeaderMap Adds headers specified in the Map
Headers Adds headers supplied in the value
HTTP Uses “CUSTOM” value in the “method” element for a request
Multipart Denotes that the request body is multi-part
OPTIONS Make an OPTIONS request
Part Used with @Multipart  request and denotes a single part of it
PartMap Denotes name and value parts of a multi-part request
PATCH Make a PATCH request
Path Named replacement in a URL path segment
POST Make a POST request
PUT Make a PUT request
Query Query parameter appended to the URL
QueryMap Query parameter keys and values appended to the URLF
QueryName Query parameter appended to the URL that has no value
Streaming @Streaming  treats the response body as it is as received from responses
Url URL resolved against the base URL

Exploring Retrofit Annotations

Annotations are the medium used on the interface methods and their parameters. They indicate how a request will be handled.

Annotations used with Request Method

For retrofit, it is essential that every method must have an HTTP annotation that provides the request method and relative URL. The relative URL of the resource must be specified in the annotation, using one of the five built-in request annotations: GET, POST, PUT, DELETE, AND HEAD. Example:
@GET(“persons/list”)

And query parameters can also be specified in the URL as:

@GET(“persons/list?sort=desc”)

Annotation used to manipulate URL

To update the request URL dynamically, replacement blocks and parameters on the method are used. A replacement block is an alphanumeric string enclosed within curly braces ({ and }), and the corresponding parameter must be annotated with @Path using the same string. Example:
@GET(“group/{id}/persons”)

Call<List<Persons>> groupList(@Path(“id) int groupId);
To add query parameters:
@GET(“group/{id}/persons”)

Call<List<Persons>>groupList(@Path(“id”) int groupId, @Query(“sort”) String sort);
To make query parameter more complex, a Map can be used:
@GET(“group/{id}/persons”)

Call<List<Persons>> groupList(@Path(“id”) int  groupId, @QueryMap Map<String, String> options);

Body Annotation

An object can also be used as an HTTP request body with the @Body annotation: Example:  
@POST(“persons/new”)

Call<Persons> createPerson(@Body Person person);

Sending Form-Encoded data

To send form-encoded data @FormUrlEncoded annotation is used.
Example:
@FormUrlEncoded

@POST(“user/edit”)

Call<Person> updatePerson(@Field(“firstName”) String fname, @Field(“lastName”) String lname);

Sending Multipart Data

@Multipart and @Part annotations are used to serve the multipart requests
Example:
@Multipart

@PUT(“user/photo”)

Call<Person> updatePerson(@Part(“photo”) RequestBody photo, @Part(“title”) RequestBody title);

Manipulating HEADER

@Headers annotation is used to set static headers for a method.
Example:
@Headers(“Cache-Control: max-age=640000”)

@GET(“widget/list”)

Call<List<Widget>> widgetList();

@Header annotation is used to update the request header dynamically, and it is necessary to provide a corresponding parameter to the @Header.
Example:
@GET(“user”)

Call<Person> getPerson(@Header(“Authorization”) String authorization)

@HeaderMap annotation is used to serve query parameters which has more complex header combination
Example:
@GET(“user”)

Call<Person> getPerson(@HeaderMap Map<String, String> headers)

Retrofit class configuration

Retrofit is a class inside retrofit2package, which is used to turn API interfaces into callable objects. There is only one type i.e. OkHttp’sResponseBody type,retrofit can deserialize HTTP bodies. If we want to add support for other types, converters can be used to deserialize. This is a list of some popular converters:
Converter Library
Gson com.squareup.retrofit2:converter-gson
Jackson com.squareup.retrofit2:converter-jackson
Moshi com.squareup.retrofit2:converter-moshi
Protobuf com.squareup.retrofit2:converter-protobuf
Wire com.squareup.retrofit2:converter-wire
Simple XML com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed and String) com.squareup.retrofit2:converter-scalars
We can add the converter dependency by getting it from Maven Central repository, or copy the code:
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.3.0</version>
</dependency>

Custom converter

Sometimes, we have different types of content-formats e.g. YAML, txt, or any other. To communicate with these types of API, we need a different converter. Retrofit provides the facility to create our own converter, and this can be easily achieved by creating a class that extends the Converter.Factory class, and pass in its instance when building the adapter. A simple example that demonstrate Gson converter implementation:
Retrofit retrofit = new Retrofit.Builder().baseUrl(“https://api.example.com”)
.addConverterFactory(GsonConverterFactory.create()).build();
RetroService service = retrofit.create(RetroService.class);

How to model the API with Retrofit?

Retrofit is very simple to understand and use. In this example, we are using the @GET annotation, and that will return the data in JSON format.
{
Login: “retroman”,
Id: 3,
url: “https://api.example.com/users/retroman”,
//some more lines can be here but we will use this only
}
Because retrofit works by modeling the base URL, so the base URL here is "https://api.example.com/users/retroman". Now, we will model the Employee class:  
Public class Employee {
Private String login;
Private long id;
Private String url;
// setters and getters here
}
Public interface EmployeeService {Now, use retrofit annotations to model the interface:
@GET(“/employee”)
Public Call<List<Employee>> getEmployee(@Query (“per_department”) int per_department,
@Query(“departments”) int departments);
@GET(“/employee/{employeeName}”)
Public Call<Employee> getEmployee(@Path(“employeeName”) String employeeName);
}
To generate working implementations, metadata is provided with annotations, so @GET annotation serves the purpose by telling the client which HTTP method to use on which resource. In our example, we provide the base URL as “https://api.example.com” and it will send the request to “https://api.example.com/employee”. The leading forward slash “/” in “/employee” tells the retrofit that is an absolute path on the host. The parameters used in @Query annotation are entirely optional and can be passed as null, the retrofit will ignore these parameters if they do not have values. And @Path annotation used to specify the path parameter.

Famous Synchronous/ Asynchronous API

Let’s build our Retrofit object to construct an HTTP request call:
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

Retrofit retrofit = new Retrofit.Builder().baseUrl(“https://api.example.com/”)

.addConverterFactory(GsonConverterFactory.create()).client(httpClient.build()).build();
Retrofit uses the base URL to construct the required object, and Gson (GsonConverterFactory)converter is used here to parse the data we are sending and receiving and map our JSON data to the Employee class, as we created earlier. Here, we used OkHttpClient, which is an HTTP & HTTP/2 client for Java and Android applications. OkHttpClient is used for connecting to the server and sending & retrieval of information. Now, we will create our service call:
EmployeeService  service = retrofit.create(EmployeeService.class);

Call<Employee> callSync  = service.getEmployee(“xyz”);

Try {

Response<Employee> response = callSync.execute();

Employee employee = response.body();

} catch (Exception ex) {

Ex.printStackTrace();

}
Retrofit constructs the service interface by injecting the necessary code inside to make the request as per our previous annotations. Then, we get a Call<Employee> object to execute the request to example.com API. The method,  execute(), is the most important method here as this is the method which is used to execute a call synchronously and while transferring the data it will block the current thread. When the call is executed successfully, we can now retrieve the body of the response on an Employee object, just with the help of GsonConverterFactory.
EmployeeService service = retrofit.create(EmployeeService.class);

Call<Employee> callAsync = service.getEmployee(“xyz”);

callAsync.enqueue(new Callback<Employee>() {

@Override

Public void onResponse(Call<Employee> call, Response<Employee> response) {

Employee employee = response.body();

}

@Override

Public void onFailure(Call<Employee> call, Throwable throwable) {

System.out.println(throwable);

}

}
Here, we used enqueue()method in place of execute() method, because it takes the Callback<Employee> interface as a parameter to handle the success or failure of the request. It will be executed in a separate thread. We can get the body as before after finishing of the call.