JQuickCurl Meets Spring Boot: Turn Raw curl into Injectable HTTP Beans in 10 Minutes

java dev.to

Spring Boot developers reach for RestTemplate or WebClient out of habit, but they're both still imperative builders: you hand-code the URL, the headers, and the body every single time. JQuickCurl brings a different workflow into your Spring Boot project — you define HTTP calls as curl commands on an interface, and Spring treats that interface's proxy like any other bean you can @Autowired.

This tutorial walks through a real Spring Boot setup step by step:

  • Adding the dependency.
  • Declaring a curl-powered service interface.
  • Exposing the proxy as a Spring bean.
  • Loading global HTTP settings from a properties file.
  • Calling everything from a @RestController.

Note: JQuickCurl ships as a plain library (no Spring Boot starter yet). Wiring it as a @Configuration bean is a few lines of code and keeps full control in your hands.

Step 1: Dependencies

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.5</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>io.github.paohaijiao</groupId>
        <artifactId>jquick-curl</artifactId>
        <version>2.5.0</version>
    </dependency>
</dependencies>
Enter fullscreen mode Exit fullscreen mode

Step 2: Declare a curl-Driven Service Interface

We call the public JSONPlaceholder API to fetch a "todo" item. Note the signature convention: the method receives a JQuickCurlReq, and its return type is a domain object.

import com.github.paohaijiao.anno.JCurlCommand;
import com.github.paohaijiao.domain.req.JQuickCurlReq;

public interface TodoApi {

    @JCurlCommand("curl -X GET https://jsonplaceholder.typicode.com/todos/1")
    TodoBean getTodo(JQuickCurlReq request);

    @JCurlCommand("curl -X POST https://jsonplaceholder.typicode.com/todos "
            + "-H 'Content-Type: application/json' "
            + "-d '{\"title\":\"learn jquick-curl\",\"completed\":false}'")
    TodoBean createTodo(JQuickCurlReq request);
}
Enter fullscreen mode Exit fullscreen mode

A couple of Java-syntax tricks used above that will save you headaches:

  • Concatenated string literals are compile-time constants, so they're perfectly valid inside annotations — long curl commands stay readable.
  • Inner double quotes inside the JSON body must be escaped (\"), exactly as in any Java string.

The domain bean is a plain POJO (the response converter maps JSON onto its fields):

public class TodoBean {
    private long userId;
    private long id;
    private String title;
    private boolean completed;

    // getters and setters omitted for brevity
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Register the Proxy as a Spring Bean

JCurlInvoker.createProxy() returns a JDK proxy of your interface. We turn that into a singleton bean, so every controller or service can @Autowired TodoApi and the proxy — and its OkHttp transport — is created only once.

import com.github.paohaijiao.config.JQuickCurlConfig;
import com.github.paohaijiao.executor.JCurlInvoker;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HttpApiConfig {

    // Optional: apply global HTTP settings (timeouts, pool, retry) at startup.
    public HttpApiConfig() throws Exception {
        JQuickCurlConfig.getInstance()
                .loadFromClasspathResource("quick-curl.properties");
    }

    @Bean
    public TodoApi todoApi() {
        return JCurlInvoker.createProxy(TodoApi.class);
    }
}
Enter fullscreen mode Exit fullscreen mode

JQuickCurlConfig is a process-wide singleton; the fluent builders below are also available if you prefer code over properties:

JQuickCurlConfig.getInstance()
        .connectTimeout(3, TimeUnit.SECONDS)
        .readTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .maxRetryCount(2)
        .followRedirects(true);
Enter fullscreen mode Exit fullscreen mode

Step 4: Properties-Driven Tuning

Place src/main/resources/quick-curl.properties on the classpath and load it with loadFromClasspathResource(...) (keys shown here are the ones this API reads today):

quick.curl.connect.timeout=3000
quick.curl.read.timeout=10000
quick.curl.write.timeout=10000
quick.curl.pool.max.idle=20
quick.curl.pool.keep.alive=300000
quick.curl.max.retry.count=2
Enter fullscreen mode Exit fullscreen mode

Now your non-functional requirements (timeouts, connection pool, retry budget) live in configuration while your request definitions live in code — no more hunting for magic numbers inside service classes.

Step 5: Consume the Bean from a Controller

import com.github.paohaijiao.domain.req.JQuickCurlReq;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TodoController {

    private final TodoApi todoApi;

    public TodoController(TodoApi todoApi) {
        this.todoApi = todoApi;
    }

    @GetMapping("/api/todos/1")
    public TodoBean getTodo() {
        return todoApi.getTodo(new JQuickCurlReq());
    }

    @PostMapping("/api/todos")
    public TodoBean createTodo() {
        return todoApi.createTodo(new JQuickCurlReq());
    }
}
Enter fullscreen mode Exit fullscreen mode

Start the application and test it:

mvn spring-boot:run
curl http://localhost:8080/api/todos/1
Enter fullscreen mode Exit fullscreen mode

Response:

{"userId":1,"id":1,"title":"delectus aut autem","completed":false}
Enter fullscreen mode Exit fullscreen mode

The controller stays clean: no RestTemplate, no URL constants, no header maps — the HTTP knowledge is encapsulated in @JCurlCommand annotations.

Summary

Integrating JQuickCurl into Spring Boot only requires three small pieces: a curl-annotated interface, one @Configuration class that exports its proxy as a bean, and an optional properties load for global tuning. From there, @Autowired works exactly as it does with any Spring-managed HTTP abstraction.

For a complete series context, all examples build on the dromara/jquick-curl project (Apache-2.0). In Post 3 we compare JQuickCurl against OkHttp, RestTemplate, and OpenFeign so you can decide, with evidence, when it deserves a place in your architecture.

java #springboot #httpclient #opensource #java-library

Source: dev.to

arrow_back Back to Tutorials