Master Retrofit in Spring Boot: Seamless HTTP Calls with Minimal Code

This tutorial walks through integrating the Retrofit HTTP client into Spring Boot using the retrofit‑spring‑boot‑starter, covering dependency setup, interface definition, token handling, global interceptors, and essential configuration such as logging, timeouts, and retry policies.

macrozheng
macrozheng
macrozheng
Master Retrofit in Spring Boot: Seamless HTTP Calls with Minimal Code

Introduction

Retrofit is a type‑safe HTTP client framework for Android and Java that lets you declare interfaces to make HTTP requests, avoiding repetitive connection and response parsing code. It has over 43k stars on GitHub.

The official Retrofit project does not provide a Spring Boot starter, so the community created retrofit-spring-boot-starter to integrate Retrofit quickly with Spring Boot and add many enhancements.

Usage

Using Retrofit in a Spring Boot project is straightforward; the following steps demonstrate the process.

Dependency Integration

Add the starter dependency to your pom.xml:

<!-- Retrofit related dependency -->
<dependency>
  <groupId>com.github.lianjiatech</groupId>
  <artifactId>retrofit-spring-boot-starter</artifactId>
  <version>${retrofit-start.version}</version>
</dependency>

Basic Usage

We will call the login and brand management APIs of the mall e‑commerce project as an example.

The mall project is a Spring Boot 3 + Vue e‑commerce system (GitHub ★60K) that supports a full order workflow.

Boot project: https://github.com/macrozheng/mall

Cloud project: https://github.com/macrozheng/mall-swarm

Tutorial site: https://www.macrozheng.com

First, start the mall-admin service and configure its base URL in application.yml:

remote:
  baseUrl: http://localhost:8080/

Define a Retrofit client interface for the admin service:

@RetrofitClient(baseUrl = "${remote.baseUrl}")
public interface UmsAdminApi {
    @POST("admin/login")
    CommonResult<LoginResult> login(@Body LoginParam loginParam);
}

Inject the client into a controller and call the remote login API:

@RestController
@RequestMapping("/retrofit")
public class RetrofitController {
    @Autowired
    private UmsAdminApi umsAdminApi;
    @Autowired
    private TokenHolder tokenHolder;

    @PostMapping("/admin/login")
    public CommonResult<LoginResult> login(@RequestParam String username,
                                            @RequestParam String password) {
        CommonResult<LoginResult> result = umsAdminApi.login(new LoginParam(username, password));
        if (result.getData() != null) {
            tokenHolder.putToken(result.getData().getTokenHead() + " " + result.getData().getToken());
        }
        return result;
    }
}

Store the token in the HTTP session with a simple helper class:

@Component
public class TokenHolder {
    public void putToken(String token) {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();
        request.getSession().setAttribute("token", token);
    }
    public String getToken() {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();
        Object token = request.getSession().getAttribute("token");
        return token != null ? (String) token : null;
    }
}

Create an annotation‑based interceptor to add the token to brand‑related requests:

@Component
public class TokenInterceptor extends BasePathMatchInterceptor {
    @Autowired
    private TokenHolder tokenHolder;

    @Override
    protected Response doIntercept(Chain chain) throws IOException {
        Request request = chain.request();
        if (tokenHolder.getToken() != null) {
            request = request.newBuilder()
                .header("Authorization", tokenHolder.getToken())
                .build();
        }
        return chain.proceed(request);
    }
}

Define the brand API with the interceptor applied:

@RetrofitClient(baseUrl = "${remote.baseUrl}")
@Intercept(handler = TokenInterceptor.class, include = "/brand/**")
public interface PmsBrandApi {
    @GET("brand/list")
    CommonResult<CommonPage<PmsBrand>> list(@Query("pageNum") Integer pageNum,
                                            @Query("pageSize") Integer pageSize);
    @GET("brand/{id}")
    CommonResult<PmsBrand> detail(@Path("id") Long id);
    @POST("brand/create")
    CommonResult create(@Body PmsBrand pmsBrand);
    @POST("brand/update/{id}")
    CommonResult update(@Path("id") Long id, @Body PmsBrand pmsBrand);
    @GET("brand/delete/{id}")
    CommonResult delete(@Path("id") Long id);
}

Inject PmsBrandApi into a controller and expose CRUD endpoints that delegate to the remote service.

@RestController
@RequestMapping("/retrofit")
public class RetrofitController {
    @Autowired
    private PmsBrandApi pmsBrandApi;

    @GetMapping("/brand/list")
    public CommonResult<CommonPage<PmsBrand>> listBrand(@RequestParam(defaultValue = "1") Integer pageNum,
                                                       @RequestParam(defaultValue = "3") Integer pageSize) {
        return pmsBrandApi.list(pageNum, pageSize);
    }
    // other CRUD methods omitted for brevity
}

For a global request header, implement a global interceptor:

@Component
public class SourceInterceptor implements GlobalInterceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Request newReq = request.newBuilder()
            .addHeader("source", "retrofit")
            .build();
        return chain.proceed(newReq);
    }
}

Configuration

Retrofit offers several common configuration options such as logging, timeout, and retry.

Logging

Set retrofit.global-log.log-strategy to body for full request/response logs.

retrofit:
  global-log:
    enable: true
    log-level: info
    log-strategy: body

Global Timeout

retrofit:
  global-timeout:
    connect-timeout-ms: 3000
    read-timeout-ms: 3000
    write-timeout-ms: 35000
    call-timeout-ms: 0

Global Retry

retrofit:
  global-retry:
    enable: true
    interval-ms: 100
    max-retries: 2
    retry-rules:
      - response_status_not_2xx
      - occur_exception

Conclusion

Retrofit provides an elegant way to make HTTP calls in Spring Boot applications, offering features beyond the traditional Feign approach, including support for microservice calls and circuit‑breaker capabilities.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootRetrofitHTTP client
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.