title: Android (Java) - POST (with headers) with Retrofit 2.1.0
body: <p>I need to integrate a <em>RESTful API</em> called SMMRY into my Android App. This API does automatic text summary of an URL or block of text that is sent to it.
  I am using <em>Retrofit 2.1.0</em> as networking library.</p>
  
  <p>I have managed to put URL text summarization working perfectly, so when I pass the URL then it does the text summary and provides me back.</p>
  
  <p>But I am unable to correctly implement the POST request by sending the appropriate parameters (which include headers, etc), so that it does the summary of block of text. </p>
  
  <p>I think that the problem is that I do not pass the headers correctly. I have tried 3 different ways to pass them, but I am getting "null" value response everytime. Firstly, I tried to add <em>@Headers</em> before the POST request (which I think was the correct way); Secondly, I tried to pass the header as a parameter; and Lastly, by managing request headers in OkHttp Interceptor. But nothing worked, or something in my code is not well implemented ... </p>
  
  <p>1 page documentation of the API (with Example implementation in PHP): <a href="http://smmry.com/api" rel="nofollow noreferrer">http://smmry.com/api</a></p>
  
  <p>The Following is the full code (I have commented all the ways in which I try to pass headers, so is easy to come up with what can be the correct way or how should I correct it):</p>
  
  <p><strong>MainActivity.java</strong></p>
  
  <pre><code>public class MainActivity extends AppCompatActivity {
  
      public static final String SM_API_KEY= "XXXXXXXXX"; // My API Key (which can be obtained by their site )
  
      public static final String URL="http://www.abola.pt/nnh/ver.aspx?id=639170";
  
      public static final String longText= "Robert Catesby (1572?–1605) was the leader of the failed Gunpowder Plot of 1605, " +
              "commemorated in Great Britain every 5 November as Guy Fawkes Night. His family were prominent recusant Catholics." +
              " A letter sent anonymously to William Parker, 4th Baron Monteagle, alerted the authorities, and on the eve of the planned explosion, " +
              "during a search of Parliament, Fawkes was found guarding the barrels of gunpowder, and arrested. Catesby and the remaining plotters made a " +
              "stand against a 200-strong company of armed men at Holbeche House in Staffordshire, where he was shot and killed. As a warning to others, his body" +
              " was exhumed and his head exhibited outside Parliament";
  
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
  
          if (SM_API_KEY.isEmpty()){
              Log.d("SM_KEY","SM_API_KEY not available");
              return;
          }
  
          SmmryAPIInterface apiService =
                  SmmryAPIClient.getClient().create(SmmryAPIInterface.class);// No headers
  
          SmmryAPIInterface apiService2 =
                  SmmryAPIClient.getClient2().create(SmmryAPIInterface.class); // client with headers, NOT USED RIGHT NOW
  
          /* Encode the URL when summarizing by URL - which is working OK*/
          String link = null;
          try {
              link = URLEncoder.encode(URL, "utf-8");
          } catch (UnsupportedEncodingException e) {
  
          }
  
  
          // Summary by URL: Working properly, the following commented lines are to call to URL summary ...
  
          /*Call&lt;SmmaryResponse&gt; call = apiService.getSummaryURL(SM_API_KEY,1,null,null,null,link);
          call.enqueue(new Callback&lt;SmmaryResponse&gt;() {
              @Override
              public void onResponse(Call&lt;SmmaryResponse&gt;call, Response&lt;SmmaryResponse&gt; response) {
                  String sm_api_content = String.valueOf(response.body().getSm_api_content());
                  //String sm_api_content = response.errorBody().toString();
  
                  Log.e("Resumo", sm_api_content);
              }
  
              @Override
              public void onFailure(Call&lt;SmmaryResponse&gt;call, Throwable t) {
                  // Log error here since request failed
                  Log.e("Erro", t.toString());
              }
          });*/
  
  
          // Summary by Text : THE PROBLEM IS HERE!:
          String header = "100-continnue";
          Call&lt;SmmaryResponse&gt; call2 = apiService.getSummaryText(SM_API_KEY,
                                                                  /*header,*/  // TRIED TO PASS THE HEADER HERE, BUT DID NOT WORK ...
                                                                  longText, 2, null, null, null);
          call2.enqueue(new Callback&lt;SmmaryResponse&gt;() {
              @Override
              public void onResponse(Call&lt;SmmaryResponse&gt;call, Response&lt;SmmaryResponse&gt; response) {
                  String sm_api_content = String.valueOf(response.body().getSm_api_content());
  
                  Log.e("Summary longText", sm_api_content);
              }
  
              @Override
              public void onFailure(Call&lt;SmmaryResponse&gt;call, Throwable t) {
                  // Log error here since request failed
                  Log.e("Erro", t.toString());
              }
          });
  
      }
  }
  </code></pre>
  
  <p><strong>SmmaryResponse.java</strong></p>
  
  <pre><code>public class SmmaryResponse {
      /*
          Currently in this class I am only using getSm_api_content(), which contains the actual summary ... This is the model class
       */
  
      private String sm_api_content;
  
      public SmmaryResponse(String sm_api_content) {
          this.sm_api_content = sm_api_content;
      }
  
      // the only method I am currently using, to get the summary
      public String getSm_api_content() {
          return sm_api_content;
      }
  }
  </code></pre>
  
  <p><strong>SmmryAPIClient.java</strong></p>
  
  <pre><code>public class SmmryAPIClient {
  
      /*
        To send network requests to an API, we need to use the Retrofit Builder class and specify the base URL for the service.
       */
  
      public static final String BASE_URL = "http://api.smmry.com/";
  
      private static Retrofit retrofit = null;
      private static Retrofit retrofit2 = null;
  
  
      /*Method to get the client*/
      public static Retrofit getClient() {
          if (retrofit == null) {
              retrofit = new Retrofit.Builder()
                      .baseUrl(BASE_URL)
                      .client(getRequestHeader())
                      .addConverterFactory(GsonConverterFactory.create())
                      .build();
          }
          return retrofit;
      }
  
      /* Method to set timeout in Retrofit library */
      private static OkHttpClient getRequestHeader() {
          OkHttpClient httpClient = new OkHttpClient.Builder()
                  .connectTimeout(100, TimeUnit.SECONDS)
                  .writeTimeout(100, TimeUnit.SECONDS)
                  .readTimeout(300, TimeUnit.SECONDS)
                  .build();
          return httpClient;
      }
  
      /*The following two methods have the purpose to create client, but this time with Headers */
      public static Retrofit getClient2() {
          if (retrofit2 == null) {
              retrofit2 = new Retrofit.Builder()
                      .baseUrl(BASE_URL)
                      .client(getRequestHeader2())
                      .addConverterFactory(GsonConverterFactory.create())
                      .build();
          }
          return retrofit2;
      }
  
      /* Method to set timeout + headers in Retrofit library */
      private static OkHttpClient getRequestHeader2() {
          OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
          httpClient.addInterceptor(new Interceptor() {
              @Override
              public Response intercept(Interceptor.Chain chain) throws IOException {
                  Request original = chain.request();
  
                  Request request = original.newBuilder()
                          //.addHeader("Content-Type", "text/plain; charset=utf-8")
                          .addHeader("Expect:", "100-continue") //  // TRIED TO PASS THE HEADER HERE, BUT DID NOT WORK ...
                          //.method(original.method(), original.body())
                          .build();
                  return chain.proceed(request);
              }
          })
                  .connectTimeout(100, TimeUnit.SECONDS)
                  .writeTimeout(100, TimeUnit.SECONDS)
                  .readTimeout(300, TimeUnit.SECONDS);
          OkHttpClient client = httpClient.build();
          return client;
      }
  }
  </code></pre>
  
  <p><strong>SmmryAPIInterface.java</strong></p>
  
  <pre><code>public interface SmmryAPIInterface {
  
      /*
      * The following two methods are implemented:
      *   getSummaryURL: method to request for the summary by providing an URL (SM_URL parameter to send URL)
      *   getSummaryText: method to request for the summary by providing a block of text (sm_api_input parameter to send block of text)
      *   Use of any optional parameters provided by Smmry, like SM_LENGTH ,SM_WITH_BREAK, etc is implemented
      */
  
      /* Pass null value strictly to optional parameters if not needed.*/
      @POST("/")
      Call&lt;SmmaryResponse&gt; getSummaryURL(@Query("SM_API_KEY") String apiKey,
                                         @Query("SM_LENGTH") Integer length,
                                         @Query("SM_WITH_BREAK") Boolean wbreak,
                                         @Query("SM_QUOTE_AVOID") Boolean quote,
                                         @Query("SM_KEYWORD_COUNT") Integer N,
                                         @Query("SM_URL") String urlSite);
  
  
      /* Pass null value strictly to optional parameters if not needed.*/
  
      //@Headers("Expect: 100-continue") // TRIED TO WRITE THE HEADER HERE, BUT DID NOT WORK ...
      @POST("/")
      Call&lt;SmmaryResponse&gt; getSummaryText(@Query("SM_API_KEY") String apiKey,
                                          //@Header("Expect:") String header, // TRIED TO WRITE THE HEADER HERE, BUT DID NOT WORK ...
                                          @Query("sm_api_input") String bText,
                                          @Query("SM_LENGTH") Integer length,
                                          @Query("SM_WITH_BREAK") Boolean wBreak,
                                          @Query("SM_QUOTE_AVOID") Boolean quote,
                                          @Query("SM_KEYWORD_COUNT") Integer N);
  }
  </code></pre>
  
  <p>I am stuck on this for few days now, and tried lot of things, but do not understand what I am doing wrong. Any help will be greatly appreciated.
  Thanks.</p>