Retrofit Android Example : Sending HTTP GET, POST Request

Spread knowledge

In our last tutorial we discussed about how to send a network request using Volley Library, while Volley is a widely used network library for basic HTTP operations there is one more library which is quite popular among Android developers- Retrofit. In fact many developers prefer Retrofit over Volley due to its ease of use, performance, extensibility etc.

Retrofit is basically an HTTP client for Android and Java developed by the awesome folks at Square. It uses OKHttp by default for network operations. What makes it unique is that with Retrofit you don’t need to worry about parsing the response – meaning de-serialization is handled in the background itself. You just need to configure any convertor library (GSON, Jackson etc) and the job is done.

In this example we will develop an application which will send a network request with Retrofit and display the response. We will be using OpenWeather API to fetch current weather details. Its a free API service which provides a number of APIs to fetch weather details anywhere on the Globe. You just need to register to obtain the API key. Read this for more

API:
https://api.openweathermap.org/data/2.5/weather?q=London,uk

Sample JSON Response

{  
   "coord":{  
      "lon":-0.13,
      "lat":51.51
   },
   "weather":[  
      {  
         "id":300,
         "main":"Drizzle",
         "description":"light intensity drizzle",
         "icon":"09d"
      }
   ],
   "base":"stations",
   "main":{  
      "temp":280.32,
      "pressure":1012,
      "humidity":81,
      "temp_min":279.15,
      "temp_max":281.15
   },
   "visibility":10000,
   "wind":{  
      "speed":4.1,
      "deg":80
   },
   "clouds":{  
      "all":90
   },
   "dt":1485789600,
   "sys":{  
      "type":1,
      "id":5091,
      "message":0.0103,
      "country":"GB",
      "sunrise":1485762037,
      "sunset":1485794875
   },
   "id":2643743,
   "name":"London",
   "cod":200
}

Step 1 : Importing Retrofit Dependency

First step as always is to add the necessary dependencies to the build.gradle file .

compile 'com.squareup.retrofit2:retrofit:2.4.0'

Apart from the retrofit client dependency we also need to add convertor library based on how we want to deserialize the response. Following are different type of convertors available

  • Gsoncom.squareup.retrofit2:converter-gson
  • Jacksoncom.squareup.retrofit2:converter-jackson
  • Moshicom.squareup.retrofit2:converter-moshi
  • Protobufcom.squareup.retrofit2:converter-protobuf
  • Wirecom.squareup.retrofit2:converter-wire
  • Simple XMLcom.squareup.retrofit2:converter-simplexml
  • Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

I will be using Gson for this example

Step 2 : Creating POJOs

As I mentioned above deserialization of response is handled by Retrofit itself. But to enable it we need to create POJOs(Plain Old Java Objects) for the JSON response in lines with Convertor library used.

A very simple way to create POJOs for the response is available at this site . We just need to paste the response and select the annotation scheme and it creates POJOs along with the annotations compatible with the library selected.

  • In this example, we are using Gson library for deserialization. Therefore while creating POJOs I have added @SerializedName annotation. This annotation maps the given variable to the respective key in JSON response

 

public class WResponse {

    @SerializedName("base")
    @Expose
    private String base;
    @SerializedName("main")
    @Expose
    private Main main;
    @SerializedName("dt")
    @Expose
    private Integer dt;
    @SerializedName("id")
    @Expose
    private Integer id;
    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("cod")
    @Expose
    private Integer cod;

    public String getBase() {
        return base;
    }

    public void setBase(String base) {
        this.base = base;
    }

    public Main getMain() {
        return main;
    }

    public void setMain(Main main) {
        this.main = main;
    }

    public Integer getDt() {
        return dt;
    }

    public void setDt(Integer dt) {
        this.dt = dt;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getCod() {
        return cod;
    }

    public void setCod(Integer cod) {
        this.cod = cod;
    }

}

 

  • You must have noticed that my POJO doesnt contain variables for a lot of parameters in JSON response (Only JSON keys which are defined in WResponse.java will  be deserialized). I have ignored JSON objects which are of no use in this example thereby saving us from creating lot of Java classes.
  • The only other POJO I will be creating is Main.java. This is with respect to the “main” key JSON Object in the response

 

public class Main {

    @SerializedName("temp")
    @Expose
    private Double temp;
    @SerializedName("pressure")
    @Expose
    private Double pressure;
    @SerializedName("humidity")
    @Expose
    private Integer humidity;
    @SerializedName("temp_min")
    @Expose
    private Double tempMin;
    @SerializedName("temp_max")
    @Expose
    private Double tempMax;
    @SerializedName("sea_level")
    @Expose
    private Double seaLevel;
    @SerializedName("grnd_level")
    @Expose
    private Double grndLevel;

    public Double getTemp() {
        return temp;
    }

    public void setTemp(Double temp) {
        this.temp = temp;
    }

    public Double getPressure() {
        return pressure;
    }

    public void setPressure(Double pressure) {
        this.pressure = pressure;
    }

    public Integer getHumidity() {
        return humidity;
    }

    public void setHumidity(Integer humidity) {
        this.humidity = humidity;
    }

    public Double getTempMin() {
        return tempMin;
    }

    public void setTempMin(Double tempMin) {
        this.tempMin = tempMin;
    }

    public Double getTempMax() {
        return tempMax;
    }

    public void setTempMax(Double tempMax) {
        this.tempMax = tempMax;
    }

    public Double getSeaLevel() {
        return seaLevel;
    }

    public void setSeaLevel(Double seaLevel) {
        this.seaLevel = seaLevel;
    }

    public Double getGrndLevel() {
        return grndLevel;
    }

    public void setGrndLevel(Double grndLevel) {
        this.grndLevel = grndLevel;
    }

}

Step 3 – Defining HTTP endpoints

Retrofit divides the network request URL into two parts -Base URL and endpoint(path). Like in this case the complete endpoint is

           http://api.openweathermap.org/data/2.5/weather

  1. Base URL      –   api.openweathermap.org
  2. Path               –   /data/2.5/weather

All the HTTP request endpoints(paths) need to be defined in an interface as shown below. Every method in the interface will represent a endpoint and should specify the request type, query parameters, headers with the help of annotations. In this example we are only sending a single GET request hence we define only one method.

  • All the methods should be returning Call object which is executed to send the network request and return the response.
  • The T in Call represents the POJO class (WResponse in this case) to which the response should be deserialized.

 

public interface WeatherAPIs {

    /*
    Get request to fetch city weather.Takes in two parameter-city name and API key.
    */
    @GET("/data/2.5/weather")
    Call < WResponse > getWeatherByCity(@Query("q") String city, @Query("appid") String apiKey);

}

 

URL Manipulation

With Retrofit you can easily modify the HTTP request with the help of annotations. The various kinds of annotations available are following

  • Request Types – This annotation specifies the type of the HTTP request
    Example: @GET, @POST, @PUT ,@DELETE
  • @Query
    This annotation represents any query key value pair to be sent along with the network request
  • @Path
    This annotation implies that the passed parameter will be swapped in the endpoint path
    Example:

    /*Over here we are passing a string parameter which will eventually substituted in the request endpoint.
    Like if the passed parameter is 123 final request path will be /data/2.5/123/getDetails.
    */
    @GET("/data/2.5/{movie_id}/getDetails")
    Call < T > getMovieDatils(@Path("movie_id") String movieID);

     

  • @Field
    This is to be used along with a POST request. These define the parameters in POST request body.

    /* Over here we are sending a POST request with two fields as POST request body params */ 
    @POST("/data/2.1") 
    Call < T > postMovieDetails(@Field("userId") String userID, @Field("token") String token);

     

     

  • @Headers
    This annotation represents any header to be encoded along with the request.
    Example:

    /*
    This request is to fetch user details by passing user id in the header
    */
    @Headers("userID : 17E9817988718E7187E710E")
    @GET("/data/2.1/user")
    Call < T > fetchUserDetails();

     

Step 4 : Creating Retrofit Client

We have defined the endpoints and also created the POJOs as per the JSON response. Now we just need to convert our interface methods to a callable network request which can be executed. This is where Retrofit.Builder() comes into picture.

Retrofit object is used for adopting a Java interface to HTTP calls by using annotations on the declared methods. Create instances using the builder and pass your interface to create(java.lang.Class) to generate an implementation.

  • Create a class NetworkClient.java with a static method which will return an instance of Retrofit object as shown below
public class NetworkClient {

    public static final String BASE_URL = "http://api.openweathermap.org";

    public static Retrofit retrofit;

    /*
    This public static method will return Retrofit client
    anywhere in the appplication
    */

    public static Retrofit getRetrofitClient() {

        //If condition to ensure we don't create multiple retrofit instances in a single application
        if (retrofit == null) {

            //Defining the Retrofit using Builder
            retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL) //This is the only mandatory call on Builder object.
                .addConverterFactory(GsonConverterFactory.create()) // Convertor library used to convert response into POJO
                .build();
        }

        return retrofit;
    }

}

Step 5 : Sending the Request

Now comes the important part- sending an HTTP GET request with Retrofit and displaying the response.

  • Our UI will contain just one EditText and one Button. We will simply enter the city name in EditText and click the button. Clicking it will invoke a network request to fetch the weather details for that city.
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.irshadkumail.retro.MainActivity">
    <EditText
      android:id="@+id/city_name"
      android:layout_width="180dp"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true"
      android:layout_marginTop="32dp"
      android:hint="Enter the city name" />
    <Button
      android:id="@+id/city_click"
      android:layout_width="180dp"
      android:layout_height="wrap_content"
      android:layout_below="@id/city_name"
      android:layout_centerHorizontal="true"
      android:layout_margin="32dp"
      android:text="GET Weather" />
    <TextView
      android:id="@+id/response_text"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_below="@id/city_click" />
</RelativeLayout>

 

  • We already have a Java interface defining the GET request. Now with the help of Retrofit instance returned from NetworkClient we will create a Callable object from the interface method based on the annotations defined with it. Check the code snippet below for details

 

public class MainActivity extends AppCompatActivity {

    private EditText editText;

    private Button button;

    private TextView responseText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        init();
    }

    private void init() {
        editText = findViewById(R.id.city_name);
        button = findViewById(R.id.city_click);
        responseText = findViewById(R.id.response_text);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                fetchWeatherDetails();
            }
        });
    }

    private void fetchWeatherDetails() {

        //Obtain an instance of Retrofit by calling the static method.
        Retrofit retrofit = NetworkClient.getRetrofitClient();

        /*
        The main purpose of Retrofit is to create HTTP calls from the Java interface based on the annotation associated with each method. This is achieved by just passing the interface class as parameter to the create method
        */
        WeatherAPIs weatherAPIs = retrofit.create(WeatherAPIs.class);

        /*
        Invoke the method corresponding to the HTTP request which will return a Call object. This Call object will used to send the actual network request with the specified parameters
        */
        Call call = weatherAPIs.getWeatherByCity(editText.getText().toString(), "235bef5a99d6bc6193525182c409602c");

        /*
        This is the line which actually sends a network request. Calling enqueue() executes a call asynchronously. It has two callback listeners which will invoked on the main thread
        */
        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                /*This is the success callback. Though the response type is JSON, with Retrofit we get the response in the form of WResponse POJO class
                */
                if (response.body() != null) {
                    WResponse wResponse = response.body();

                    responseText.setText("Temp: " + wResponse.getMain().getTemp() + "\n " +
                        "Humidity: " + wResponse.getMain().getHumidity() + "\n" +
                        "Pressure: " + wResponse.getMain().getPressure());
                }
            }

            @Override
            public void onFailure(Call call, Throwable t) {
                /*
                Error callback
                */

            }
        });

    }

 

  • As you must have noticed the response callback invoked on the main thread comes with WResponse object automatically parsing JSON response. This is because we give the return type as Call while defining the method in the interface.
  • You might know that Android does not allow  network operations on the main thread therefore Retrofit handles switching to background thread on its own. The response callbacks are invoked on the main thread though.
  • With a click of the button the HTTP request is executed and weather details are fetched.  We don’t do much with the details fetched just display them on the screen . I have not used a very fancy UI to display details as our main focus for this article is to send network requests with Retrofit.20180702_064137[1]

Spread knowledge

3 Replies to “Retrofit Android Example : Sending HTTP GET, POST Request”

  1. I followed this article and found it very useful and concise with explanations that are not usually found in other places. Thank you for the consistent information.
    For the other readers who are trying to build and run this program in Android Studio:
    Add those dependency into build.gradle module app:
    implementation ‘com.squareup.retrofit2:retrofit:2.4.0’
    implementation ‘com.squareup.retrofit2:converter-gson:2.2.0’
    implementation ‘com.google.code.gson:gson:2.8.5’
    implementation ‘org.apache.commons:commons-lang3:3.6’
    Create WeatherAPIs.java interface file with the content described into the article.
    If you want generate POJOs JAVA classes by yourself as this article is needing you must give the follow JSON to http://www.jsonschema2pojo.org :
    {
    “base”:”stations”,
    “main”:{
    “temp”:280.32,
    “pressure”:1012,
    “humidity”:81,
    “temp_min”:279.15,
    “temp_max”:281.15
    },
    “dt”:1485789600,
    “id”:2643743,
    “name”:”London”,
    “cod”:200
    }

Leave a Reply

Your email address will not be published. Required fields are marked *