Poutsma Principles Consulting & Training

Designing for Ctrl + Space

Part 1 of Crafting Fluent APIs

Though undoubtedly there are still vi and Notepad users out there, code completion has become the primary way most developers interact with your API. As such, it is worth considering what they see when they hit Ctrl + Space in their IDE of choice.

APIs with a clean, minimal completion surface are easier to use and harder to misuse—especially when designed fluently, using method chaining and step-by-step invocation.

This is Part 1 of a series entitled Crafting Fluent APIs, where I explore various design considerations behind fluent API design. You can find an overview of the series here.


Most developers, when exploring an unfamiliar API, do not start with the documentation. They type an object name, hit Ctrl + Space, and scan the list of suggestions. That list becomes both documentation and user guide.

Each additional option in that list increases cognitive load. The more methods a developer has to scan and distinguish between, the harder it becomes to discover the right one. A key goal in API design, then, is to reduce the number of visible options at any given moment.

When a developer cannot see the forest for the trees, the API is too noisy. Ideally, the completion menu should contain only a few relevant choices at each step.

RestTemplate

Take the RestTemplate, introduced in Spring Framework 3. It follows the same template pattern as JdbcTemplate, JmsTemplate, and others.

Like those, RestTemplate exposes a flat surface—dozens of similar-looking methods: convenience methods per HTTP method (getForObject, postForEntity, etc.), as well as generic methods (exchange and execute) for more flexibility. Moreover, each method has three overloaded variants to be able to offer URL template variables as varargs, as a Map, or to offer the URL as a java.net.URI.

All of these appear at once, creating an overwhelming set of choices.

Method Options for RestTemplate

To be fair, RestTemplate did not start with so many methods. Over time, more were added out of necessity (like patchForObject), but each new method added surface area and complexity.

Eventually, we made the decision to stop adding features to RestTemplate. Every addition meant another overload, and another burden for the user.

WebClient and RestClient

With Spring Framework 5 and the new reactive stack, we had the opportunity to apply what we had learned. WebClient was born, and later, RestClient for the non-reactive use case.

A key design goal was to limit the number of options offered at each step, using method chaining and narrower return types to guide the developer. The implementation behind this — particularly how return types control visibility — will be covered in a future post.

What used to be a single overloaded method call in RestTemplate became a chain of calls in RestClient, each handling one concern in the HTTP exchange.

First, choose the HTTP method:

Choosing a HTTP method with RestClient

Then specify the URI. As with RestTemplate, multiple variants are supported.

Second Option for RestClient

Because the method is POST, the next step offers options for setting the request body. If this were GET, body-related methods would not appear.

Third Option for RestClient

Finally, choose how to handle the response:

Fourth Option for RestClient

Compare this to the earlier approach:

String response = 
    template.postForObject(         // method
        "https://example.com/post", // URI
        "Hello World",              // request object
        String.class);              // response type

Now, using RestClient:

String response = 
    client.post()                          // method
          .uri("https://example.com/post") // URI
          .body("Hello World")             // request object
          .retrieve()
          .body(String.class);             // response type

Each step surfaces only what is relevant at that stage—a much cleaner experience for the developer.


The Broader Lesson

The key difference between RestTemplate and RestClient lies not in what they do, but in how they guide the developer to do it.

Where RestTemplate exposes a wide, flat surface with dozens of methods and overloads, WebClient and RestClient breaks the interaction into smaller, focused steps—each with a limited set of choices. This narrowing of the completion surface at each stage reduces cognitive load and makes the API easier to explore through code completion alone.

Fluent API design is not just about chaining calls. It is about structuring the journey—helping the developer move through a series of decisions in the right order, with just the information they need, when they need it.

In modern development, code completion is the user’s first interface with your API. Designing that experience deliberately is what separates usable APIs from user-friendly APIs.

About the Author

I am Arjen Poutsma, and I help teams improve Java code, design better APIs, and manage open source—through reviews, training, and coaching. If that sounds useful, please contact me.