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.
- 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/
- 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>
- 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’s
ResponseBody 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.