Poutsma Principles Consulting & Training

Why Good APIs Are Like Ogres

Good APIs are like ogres: they have layers.

However, where an ogre hides its gentle core behind a rough exterior, an API should do the reverse: presenting a friendly surface while hiding its complexity within.

The outermost layer should be the most approachable, offering convenient shortcuts for common tasks. The innermost layer should be the most powerful, exposing all capabilities at the cost of verbosity or complexity.

An Ogre


Layers in Spring MVC

An example of layering can be found in Spring MVC. Each layer is public and designed for user consumption, but they differ in abstraction, convenience, and scope.

  1. Annotation-based layer: @Controller, @RequestMapping, and friends.
    The most user-friendly entry point: concise and expressive, though not suited for every edge case.
  2. Extension points: such as HandlerMethodArgumentResolver and HandlerMethodReturnValueHandler. These allow customization and integration while keeping the annotation model intact.
  3. Servlet API: the foundation. It defines the raw HTTP abstraction for Java web applications. If something is not possible here, it cannot be done in higher layers either.

Each layer offers a different “view” of the web programming model at its own abstraction level. You can write a Servlet that accomplishes the same as a @Controller, but it will require much more code.

Layers in WebMvc.fn

The WebMvc.fn functional API follows a similar pattern:

  1. Builders: RouterFunctions.route and related helpers.
    These provide a fluent and readable way to define routes and handlers.
  2. Component model: HandlerFunction and RouterFunction.
    A composable core that allows for extension and reuse.
  3. Servlet API: again, the foundation underneath.

Simple, Not Simplistic

The most important design rule is that higher layers must be able to reach the lower ones. Otherwise, the API becomes simplistic rather than simple: pleasant for trivial cases, but too limited for anything beyond them.

Spring provides many examples of this principle:

  • In Spring MVC, a controller method can declare a HttpServletRequest or HttpServletResponse parameter, giving access to the Servlet API when needed.
  • In WebMvc.fn, you can use a WriteFunction to directly interact with the request and response.

This ability to “peel back the layers” ensures that convenience never comes at the cost of capability.


The Broader Lesson

Every mature API should have layers. The top layers express the most common workflows in the most user-friendly terms. The lower layers expose the raw capabilities for edge cases. Higher layers should offer access to the lower layers, enabling more complex use cases.

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.