Ableron

Decentralized server-side UI composition – no gateway, no central controller.

View on GitHub

What is Ableron?

Ableron is a library for decentralized server-side UI composition. Unlike traditional solutions like nginx SSI, there’s no central component. Each service is capable of composing its own HTML using <ableron-include> tags, resolved internally. This is achieved by installing Ableron as a dependency in your service.

Why Ableron?

TL;DR: Ableron is a decentralized, efficient solution for dynamic, server-side UI composition with local caching, easy configuration, and great developer experience.

πŸ’‘

Lean Infrastructure

No need to route all traffic through a centralized infrastructure component for UI composition. Services stay independent and scalable.

πŸš€

Easy Local Development

Since includes are resolved directly within your service, local development works out of the box β€” without needing to run complex infrastructure setups.

βš™οΈ

Simple Configuration

Configure per-include settings like timeouts, fallback fragments, or static fallback content with minimal effort β€” no central coordination required.

πŸ’Ύ

Local Caching

All fragments can be cached in memory directly inside your service, based on their individual cache policy. This reduces HTTP overhead and latency β€” saving both time and money.

Ableron vs nginx SSI

Feature Ableron nginx SSI
Centralized vs Distributed Decentralized (each service composes its own UI) Centralized (nginx manages UI composition)
Developer Experience Easy local development with no extra infrastructure Requires complex infrastructure setup for local development
Scalability Scalable by design, no bottlenecks Potential bottleneck at the centralized server
Caching In-memory fragment caching per service Caching typically done at the centralized infrastructure level
Complexity Low complexity (library-based, no additional infrastructure) Higher complexity with nginx or similar infrastructure

Quickstart

Ableron provides framework integrations for Spring Boot 2, Spring Boot 3, express and fastify as well as low level implementations for Java and JavaScript.

Minimal usage example with express:

import express from 'express';
import ableron from '@ableron/express';

const app = express();
app.use(ableron());

app.get('/', function(req, res) {
  res.send('<ableron-include src="http://user-service/profile"/>');
});

app.listen(port);

More examples and documentation available in the GitHub repository.

Ableron-Tag Properties

The <ableron-include> tag is used to include fragments from external URLs into your page. It comes with various attributes and fallback options.

Required Closing Tag

The <ableron-include> tag must be properly closed. You can either use the self-closing syntax <ableron-include ... /> or explicitly close the tag with <ableron-include ...></ableron-include>.

Fallback Content

Content placed between <ableron-include> and </ableron-include> is used as fallback content in case the fragment cannot be loaded due to request timeout or erroneous response.

Attributes

  • id: A unique identifier for the include tag. This is useful for log messages and debugging.
  • src: The URL of the fragment to be included. This is the primary source of the fragment content.
  • src-timeout: Timeout for requesting the fragment URL. This can be specified in milliseconds (e.g., 2000 or 2000ms) or seconds (e.g., 2s). Defaults to the global request timeout.
  • fallback-src: The URL to a fallback fragment, in case the primary src fails to load.
  • fallback-src-timeout: Timeout for requesting the fallback-src URL. The value can be specified similarly to src-timeout.
  • primary: Denotes a fragment whose response code will be set as the HTTP response code for the entire page.
  • headers: A comma-separated list of headers that should be forwarded from the parent request to the fragment request. These headers become part of the cache key for the requested URL.
  • cookies: A comma-separated list of cookies that should be forwarded to the fragment request. These cookies also become part of the cache key for the requested URL.

Resolution Precedence

When resolving the fragment content, the precedence is as follows: src β†’ fallback-src β†’ fallback content. This ensures a robust fallback mechanism in case of failures.

Ableron-Tag Example

Here's an example of how you can use the <ableron-include> tag to include external fragments into your service response. This example demonstrates the use of several important attributes, such as src, fallback-src, headers, cookies, and fallback content.

<ableron-include
  id="header"
  src="https://header-service/api/fragments/header"
  src-timeout="2s"
  fallback-src="https://cdn-proxy/static/fallback-header"
  headers="x-ab-test-groups,x-country"
  cookies="device,consent">
  <header>Static fallback header</header>
</ableron-include>
    

In this example:

Advanced Features

⭐ Primary Includes

Ableron supports marking an <ableron-include> as primary. Primary includes are considered to be the main part of the finally composed page and thus define the HTTP response status and influence response headers.

πŸ” Cache Auto Refresh

Ableron supports automatic cache refreshing for included fragments β€” a feature designed to keep response times low and cache hit rates high.

πŸ“Š Statistics

To provide insights into what is happening during page composition, Ableron provides the opportunity to add composition statistics to the finally composed page via HTML comment. This feature is disabled by default, as you may not want to expose those statistics in your production environment.

<!-- Processed 4 includes in 93ms

Time | Include | Resolved With | Fragment Cacheability | Fragment URL
------------------------------------------------------
0ms | header | fallback content | - | -
56ms | main | remote src | not cacheable | https://content-service/main
93ms | footer | remote src | expires in 600s | https://content-service/footer
0ms | nav | cached fallback-src | expires in 10s | https://content-service/nav

Cache: 3 items, 1 hits, 3 misses, 0 successful refreshs, 0 failed refreshs
-->

FAQ

Which fragments will be cached?

Fragments will be cached, if their cache policy allows caching and if the response code is one of 200, 203, 204, 206, 300, 404, 405, 410, 414, 501.

How are redirects being handled?

In order to not introduce unwanted latency, redirects returned by src or fallback-src URLs will not be followed. Instead, the request is considered failed.

Does Ableron influence the Cache-Control of my page?

As each fragment brings its own cache policy, Ableron will adjust the cache policy of the finally composed page accordingly. The fragment with the lowest TTL defines the max-age of the page, in case max age of the page is not below it.

Contributing

All contributions are greatly appreciated. To contribute, either open an issue or fork the repository and create a pull request:

  1. Fork the repository
  2. Create your feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Added some amazing feature'
  4. Push to your branch: git push origin feature/amazing-feature
  5. Open a pull request