DEV Community

Sota
Sota

Posted on • Edited on

How to call third-party API in Spring Boot

Overview

I will introduce how to call third-party API in Spring Boot project. We'll send GET request to this resource https://sampleapis.com/api-list/coffee, then display response data in view (browser).

Prerequisites

You need these knowledge at basic level:

  • Java
  • Spring Boot
  • Thymeleaf

Development process

Create Project

Go to https://start.spring.io/ and generate a project with these dependencies:

Image description

Unzip the file and open the project in your code editor. I use Intellij community edition.

Create Controller

import com.myproject.apidemo.Coffee;

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.client.WebClient;

@Controller
public class CoffeeController {

    @GetMapping("/coffee")
    public String coffee(Model model) {
        String url = "https://api.sampleapis.com/coffee/hot";

        WebClient.Builder builder = WebClient.builder();

        String coffeeList = builder.build()
                .get()
                .uri(url)
                .retrieve()
                .bodyToMono(String.class)
                .block();

        System.out.println("---------------------");
        System.out.println(coffeeList);

        model.addAttribute("coffeeList", coffeeList);

        return "coffee";
    }
}
Enter fullscreen mode Exit fullscreen mode

If you can't import some of them, then one possible problem is Maven doesn't load your pom.xml file correctly. Reloading the project resolves this issue in my case.


You can directly type url in your browser and check the response data, it is a list of coffee in JSON format.

You can map response data to Java object if you want. For this, you need to create Coffee class and define fields that you want to hold as Coffee object. For me, Coffee class has two fields, title and description. This way, when response data maps to Coffee object, the object only holds title and description from response JSON data.

package com.myproject.todoapp;

public class Coffee {

    String title;

    String description;

    public Coffee() {
    }

    public Coffee(String title, String description) {
        this.title = title;
        this.description = description;
    }

    // getters and setters
    // toString method
}

Enter fullscreen mode Exit fullscreen mode
import com.myproject.apidemo.Coffee;

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.client.WebClient;

@Controller
public class CoffeeController {

    @GetMapping("/coffee")
    public String coffee(Model model) {
        String url = "https://api.sampleapis.com/coffee/hot";

        WebClient.Builder builder = WebClient.builder();

        List<Coffee> coffeeList = builder.build()
                .get()
                .uri(url)
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<List<Coffee>>() {
                })
                .block();

        System.out.println("---------------------");
        System.out.println(coffeeList);

        model.addAttribute("coffeeList", coffeeList);

        return "coffee";
    }
}
Enter fullscreen mode Exit fullscreen mode

In this tutorial, I prefer converting the response data to Coffee object, so I stick to second version implementation.

Create View page

Finally we need view page just to display list of coffee:

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Coffee</title>
</head>
<body>

<h3>Coffee List</h3>

<table>
    <tbody>
    <tr th:each="coffee: ${coffeeList}">
        <td th:text="${coffee.title}"></td>
        <td th:text="${coffee.description}"></td>
    </tr>
    </tbody>
</table>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Done! Now you should be able to get data from http://localhost:8080/coffee.

Refactoring code

Although we could successfully call the API, there's a room for improvement. Currently coffee method instantiates WebClient.Builder object each time when it gets called. This is unnecessary overhead. Better implementation is creating separate file that configures WebClient.Builder.

Create configuration file for WebClient:

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient(WebClient.Builder builder) {
        return builder.build();
    }
}
Enter fullscreen mode Exit fullscreen mode

Inject the Bean to our Controller class:

    private WebClient webClient;

    @Autowired
    public ToDoListController(WebClient webClient) {
        this.webClient = webClient;
    }

    @GetMapping("/coffee")
    public String coffee(Model model) {
        String url = "https://api.sampleapis.com/coffee/hot";

        List<Coffee> coffeeList = webClient
                .get()
                .uri(url)
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<List<Coffee>>() {
                })
                .block();

        // other code
    }
Enter fullscreen mode Exit fullscreen mode

Now Spring Boot automatically instantiates and manages WebClient object behind the scene.

Top comments (0)