Skip to main content
Redhat Developers  Logo
  • Products

    Platforms

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat AI
      Red Hat AI
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • View All Red Hat Products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat Developer Hub
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat OpenShift Local
    • Red Hat Developer Sandbox

      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Secure Development & Architectures

      • Security
      • Secure coding
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • Product Documentation
    • API Catalog
    • Legacy Documentation
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

The NEW API Pattern

 

October 12, 2017
Owen Rubel
Related topics:
Developer Tools
Related products:
Developer Tools

Share:

    Distributed Architectures are a lot like neural networks; all services that talk to each other need to share the I/O in and in a way that they can synchronize that information on the fly. The way the brain does is that each neuron that communicates with another has the other neuron fire back a neurotransmitter to synchronize and improve that communication in the future thus creating a pattern.

    While this behavior is almost identical to what is known as a webhook in the API world, we do not follow the same principles for API design in distributed architectures. Since the API Pattern designed in the 1970’s for centralized architectures and NOT distributed architectures, it was never intended to be used in this way and creates an architectural cross-cutting concern when used in distributed services.

    Discovery of the Architectural Cross-Cutting Concern in API’s

    I first came across this in 2013, when I was on a contract at Cisco/Apple. I was building a web app and had to make 5 API requests (one after another) to get the data I needed. The entire function took about 30 seconds and I thought to myself ‘why hasn’t anyone invented an API Monad so that one can chain all these calls using one request/response?’ That question led me down a rabbit hole of discovery.

    In looking at others attempts to do something similar to this, I only saw hardcoded chains or dynamic attempts that never resolved the redirect. When doing hardcoded chains, you still have to do a request/response with each call thus defeating the purpose and even doing it dynamically, you have to solve for the ‘redirect issue’ or you will still have to do a REQUEST/RESPONSE with each call.

    I knew that if I could merely replace the redirect with a forward, I could effectively chain the calls without having to do a redirect (see forward vs. redirect). But that would require an internal communication loop. So, I started to investigate this.

    In researching and in attempting to create the monad myself, I discovered why no one had done this: The original API pattern has a fatal flaw wherein it binds the communication logic to business logic. This flaw makes it so that communication cannot be shared without duplication of the I/O state; this becomes obvious when you realize that files such as RAML, API Blueprint, OpenAPI, Swagger, etc. are all attempting to duplicate data found in the business logic.

    This issue is what is known as a ‘cross-cutting concern‘ since the communication logic/data (which needs to be shared in the distributed architecture) is being bound to the business logic because of the API Pattern. And because the API Pattern will only cause it to occur in a distributed architecture, I dubbed it an ‘architectural cross-cutting concern’… specifically because it had to do with shared I/O across distributed services.

    I realized that no one to date had realized the issue, had isolated it or was working on resolving it; everyone had simply tried to create workarounds rather than trying to solve the underlying problem. But these workarounds created additional problems with:

    • synchronization
    • shared state
    • uptime
    • scalability
    • speed
    • performance
    • development time
    • maintenance
    • logging
    • and MUCH more

    The issue at hand was that the API pattern was a pattern designed for centralized architectures, as it didn’t share data associated I/O (the request/response) with other services in the network due to the binding created by the API pattern. When I pointed this out to the API Development Manager at Netflix (and showed him the solution) he stated: “This fixes everything we are having issues with!“

    The OLD API Pattern

    You see the original API pattern was designed in the 1970’s as a way to standardize input/output when calling a service/library. But since you are forcing the library/service to handle the input/output at the same location in the code where you handle the business logic, you are creating a binding of communication layer to business logic.

    Now in a ‘centralized architecture’, you will never see an issue with this because you don’t need to share I/O with external services on your network. You have created one single monolithic application on one server; the request/response only goes to one server and then back out to the client.

    But this binding becomes blatantly apparent in a distributed architecture where it becomes impossible for I/O data to be shared across the network without duplication or entanglement. This is what is known as a cross-cutting concern. However since this occurs ONLY in a distributed architecture, I coined the term an ‘architectural cross-cutting concern’ as echoed by my peers years later.

    This can be seen in a variety of ways in the fact that if any endpoint data changes, it must be DUPLICATED to all other services that share it. Data such as:

    • ROLES/Privileges
    • Request Method for endpoint
    • Required REQUEST data for endpoint for each ROLE
    • Required RESPONSE data for endpoint for each ROLE
    • All available Versions of endpoints
    • API Docs

    The current methodologies DO NOT SYNCHRONIZE this data (ie OpenAPI, RAML, API Blueprint, Swagger, etc.) in any way and rely on humans to synchronize all data. This is highly unreliable and ineffective and can cause higher privileges, unsynchronized endpoints and inefficient periods of downtime.

    Abstracting the Communication Layer

    The solution is what I call API Abstraction. To solve this inherent error in the pattern, one has to abstract the communication logic and data away from the business logic into a separate layer. Then synchronize the data using a ‘middle-out’ pattern; since the ‘central-version of truth’ for the data is going to be the service where the REQUEST/RESPONSE meet, we can ‘CACHE and PUSH’ state from this central point to all subscribing services in the architecture.

    First, we have to abstract all communication from the business logic. To do this we have to understand how the communication logic/data are bound to the business logic for API’s. In most modern MVC frameworks, this is done via extending a class at the controller or through annotations like so:

    @Secured(['ROLE_ADMIN', ‘ROLE_USER'])
    @RequestMapping(value="/create", method=RequestMethod.POST)
    @ResponseBody
    public ModelAndView createAddress(){
    List authorities = springSecurityService.getPrincipal().getAuthorities()
    User user
    if(authorities.contains(‘ROLE_ADMIN’)){
        if(params.id){ 
            user = User.get(params.id.toLong())
        }else{
    render(status:HttpServletResponse.SC_BAD_REQUEST)
    }
    }else{
        if(authorities.contains(‘ROLE_USER’)){
            user = User.get(principal.id)
        }
    }

    Address address = new Address(params)
    …
    address.user = user
    …
    Now naturally some of this functionality could be moved to a service…but this is merely here to show the binding of communication data/logic and it’s redundancy.
     
    Still, what if we didn’t even need to call half of this? What if the communication layer was actually abstracted so the business logic only dealt with what it was supposed to…resource management? Well, the code above would look something like this then:
    public ModelAndView createAddress(){
        User user= (params.id)?User.get(params.id.toLong()): User.get(principal.id
        Address address = new Address(params)
        address.user = user
        …
    }
    No annotations, no checks. All communication functionality has been abstracted so that each request handles it…not each controller. The controller focuses on just getting and formatting the resource. Clean and simple. This vastly reduces the amount of coding needed.
     
    But how DO we do API Abstraction?
     

    API Abstraction with the HandlerInterceptor

    As you saw in the image above for the distributed architecture, the ‘IO State’ for the API Server has the communication logic bound down at the controller. But we need to have the communication logic/data somewhere closer to where the request/response is. In addition, it would be even better if they could hand off to each other.

    In Java, we call this functionality a HandlerInterceptor. In Python, Ruby, and other languages, it is often called a Filter (though these are not always abstracted away from the controller). The HandlerInterceptor provides us with several different functions (of which the following are used):

    • preHandle: The ‘preHandle’ intercepts the REQUEST before it goes to the Controller so that preprocessing can take place.
    • postHandle: The ‘postHandle’ intercepts the RESPONSE as it returns from the Controller so that postprocessing can take place.

    By being able to intercept at these two key locations, we are able to build a layer to move all communications away from the Controller for handling the REQUEST/RESPONSE. And more importantly, we now have a way to ‘forward’ traffic back into the application (as seen above) without having to do an expensive redirect.
     

    The API NeuroTransmitter

    Bringing this all together, how do we synchronize everything in our architecture without duplication of data? Well now that we have abstracted the Communication Logic, we can easily build a sharable API Object-based upon data similar to RAML, API Blueprint, and others. I like to call this I/O State.

    I/O State contains all data separate from functionality for the API endpoints that is directly related to the REQUEST/RESPONSE.

    What this enables us to do is the following:

    1. Load these files at runtime via a master API Server and build objects into a local cache.
    2. Share these objects with all subscribing services via webhooks.
    3. Reload these files ‘on-the-fly’ without having to take services down and synchronize entire architecture.

    Should the ‘master’ API server go down, nothing in the architecture is affected, as it will have the last known state…AND the server will come up with the last known state as well.

    This enables all services in your API architecture to stay synchronized, be more secure, maintain a higher uptime, etc.

    In Conclusion…

    If you are using a distributed architecture, you will notice these issues increasingly as you scale and I have increasingly been giving these talks more and more. My advice is to move towards this model ASAP.

    If you wish to see a working example, you can visit the open source BeAPI Framework where you can download the plugin and a demo implementation, which has been tested out on EC2, Raspberry Pi and numerous other instances.

    Last updated: May 31, 2024

    Recent Posts

    • Why some agentic AI developers are moving code from Python to Rust

    • Confidential VMs: The core of confidential containers

    • Benchmarking with GuideLLM in air-gapped OpenShift clusters

    • Run Qwen3-Next on vLLM with Red Hat AI: A step-by-step guide

    • How to implement observability with Python and Llama Stack

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2025 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue