Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use HttpURLConnection or RestTemplate [duplicate]

Tags:

java

spring

Should I use HttpURLConnection in a Spring Project Or better to use RestTemplate ? In other words, When it is better to use each ?

like image 944
Z.yassine Avatar asked Dec 15 '18 16:12

Z.yassine


Video Answer


1 Answers

The HttpURLConnection and RestTemplate are different kind of beasts. They operate on different abstraction levels.

The RestTemplate helps to consume REST api and the HttpURLConnection works with HTTP protocol.

You're asking what is better to use. The answer depends on what you're trying to achieve:

  • If you need to consume REST api then stick with RestTemplate
  • If you need to work with http protocol then use HttpURLConnection, OkHttpClient, Apache's HttpClient, or if you're using Java 11 you can try its HttpClient.

Moreover the RestTemplate uses HttpUrlConnection/OkHttpClient/... to do its work (see ClientHttpRequestFactory, SimpleClientHttpRequestFactory, OkHttp3ClientHttpRequestFactory


Why you should not use HttpURLConnection?

It's better to show some code:

In examples below JSONPlaceholder used

Let's GET a post:

public static void main(String[] args) {
  URL url;
  try {
    url = new URL("https://jsonplaceholder.typicode.com/posts/1");
  } catch (MalformedURLException e) {
    // Deal with it.
    throw new RuntimeException(e);
  }
  HttpURLConnection connection = null;
  try {
    connection = (HttpURLConnection) url.openConnection();
    try (InputStream inputStream = connection.getInputStream();
         InputStreamReader isr = new InputStreamReader(inputStream);
         BufferedReader bufferedReader = new BufferedReader(isr)) {
      // Wrap, wrap, wrap

      StringBuilder response = new StringBuilder();
      String line;
      while ((line = bufferedReader.readLine()) != null) {
        response.append(line);
      }
      // Here is the response body
      System.out.println(response.toString());
    }

  } catch (IOException e) {
    throw new RuntimeException(e);
  } finally {
    if (connection != null) {
      connection.disconnect();
    }
  }
}

Now let's POST a post something:

connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type", "application/json; charset=UTF-8");

try (OutputStream os = connection.getOutputStream();
     OutputStreamWriter osw = new OutputStreamWriter(os);
     BufferedWriter wr = new BufferedWriter(osw)) {
  wr.write("{\"title\":\"foo\", \"body\": \"bar\", \"userId\": 1}");
}

If the response needed:

try (InputStream inputStream = connection.getInputStream();
     InputStreamReader isr = new InputStreamReader(inputStream);
     BufferedReader bufferedReader = new BufferedReader(isr)) {
  // Wrap, wrap, wrap

  StringBuilder response = new StringBuilder();
  String line;
  while ((line = bufferedReader.readLine()) != null) {
    response.append(line);
  }

  System.out.println(response.toString());
}

As you can see the api provided by the HttpURLConnection is ascetic.

You always have to deal with "low-level" InputStream, Reader, OutputStream, Writer, but fortunately there are alternatives.


The OkHttpClient

The OkHttpClient reduces the pain:

GETting a post:

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
    .url("https://jsonplaceholder.typicode.com/posts/1")
    .build();
Call call = okHttpClient.newCall(request);
try (Response response = call.execute();
     ResponseBody body = response.body()) {

  String string = body.string();
  System.out.println(string);
} catch (IOException e) {
  throw new RuntimeException(e);
}

POSTing a post:

Request request = new Request.Builder()
    .post(RequestBody.create(MediaType.parse("application/json; charset=UTF-8"),
        "{\"title\":\"foo\", \"body\": \"bar\", \"userId\": 1}"))
    .url("https://jsonplaceholder.typicode.com/posts")
    .build();

Call call = okHttpClient.newCall(request);

try (Response response = call.execute();
     ResponseBody body = response.body()) {

  String string = body.string();
  System.out.println(string);
} catch (IOException e) {
  throw new RuntimeException(e);
}

Much easier, right?

Java 11's HttpClient

GETting the posts:

HttpClient httpClient = HttpClient.newHttpClient();

HttpResponse<String> response = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
    .GET()
    .build(), HttpResponse.BodyHandlers.ofString());

System.out.println(response.body());

POSTing a post:

HttpResponse<String> response = httpClient.send(HttpRequest.newBuilder()
    .header("Content-Type", "application/json; charset=UTF-8")
    .uri(URI.create("https://jsonplaceholder.typicode.com/posts"))
    .POST(HttpRequest.BodyPublishers.ofString("{\"title\":\"foo\", \"body\": \"barzz\", \"userId\": 2}"))
    .build(), HttpResponse.BodyHandlers.ofString());

The RestTemplate

According to its javadoc:

Synchronous client to perform HTTP requests, exposing a simple, template method API over underlying HTTP client libraries such as the JDK {@code HttpURLConnection}, Apache HttpComponents, and others.

Lets do the same

Firstly for convenience the Post class is created. (When the RestTemplate will read the response it will transform it to a Post using HttpMessageConverter)

public static class Post {
  public long userId;
  public long id;
  public String title;
  public String body;

  @Override
  public String toString() {
    return new ReflectionToStringBuilder(this)
        .toString();
  }
}

GETting a post.

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Post> entity = restTemplate.getForEntity("https://jsonplaceholder.typicode.com/posts/1", Post.class);
Post post = entity.getBody();
System.out.println(post);

POSTing a post:

public static class PostRequest {
  public String body;
  public String title;
  public long userId;
}

public static class CreatedPost {
  public String body;
  public String title;
  public long userId;
  public long id;

  @Override
  public String toString() {
    return new ReflectionToStringBuilder(this)
        .toString();
  }
}

public static void main(String[] args) {

  PostRequest postRequest = new PostRequest();
  postRequest.body = "bar";
  postRequest.title = "foo";
  postRequest.userId = 11;


  RestTemplate restTemplate = new RestTemplate();
  CreatedPost createdPost = restTemplate.postForObject("https://jsonplaceholder.typicode.com/posts/", postRequest, CreatedPost.class);
  System.out.println(createdPost);
}

So to answer your question:

When it is better to use each ?

  • Need to consume REST api? Use RestTemplate
  • Need to work with http? Use some HttpClient.

Also worth mentioning:

  • Retrofit
  • Intro to Feign
  • Declarative REST client
like image 169
Denis Zavedeev Avatar answered Nov 15 '22 20:11

Denis Zavedeev