Skip to content
epilot-berater.de

Blog

Mappers between epilot and third-party systems with Quarkus

A Quarkus mapper for epilot: how it receives webhooks, converts data for third-party systems, calls them via REST and handles failures in operation.

By Last updated: 10 min read

A Quarkus mapper for epilot is a small, dedicated service that translates data between epilot and the rest of your system landscape. This article walks through how such a mapper is put together, what it is responsible for, and which rules keep it reliable once it is running.

I am Marcel R. G. Berger, a software developer and architect with more than 20 years of experience. I work with epilot as an external consultant and developer for apps and customisations. This piece is for IT leads at grid operators, municipal utilities and energy suppliers who need to connect other systems to epilot.

What is a mapper between epilot and surrounding systems?

A mapper is a dedicated service that translates data between epilot and another system. It accepts data in the shape one side produces and passes it on in the shape the other side expects.

That sounds like plain field mapping, but in practice there is more to it. A mapper usually carries five responsibilities.

ResponsibilityWhat the mapper doesExample
Field mappinglinks fields on one side to fields on the othera customer field in epilot becomes the matching field in a line-of-business system
Format conversionconverts data types, date formats, codes and structuresan ISO date becomes the format the target system expects
Validationchecks that required values are present and plausiblea record missing a mandatory field is rejected instead of half-transferred
Enrichmentadds data from further sourcesmaster data is looked up in a database
Error handlingdetects failures, retries calls and logs in a traceable waya system that is briefly unreachable is called again later

The mapper becomes the one place where all the rules live that only exist because two systems see the world differently. epilot itself keeps only what genuinely belongs to epilot.

When is a dedicated mapper worth it compared to a low-code flow?

A dedicated mapper is worth it as soon as you need more than a straight hand-off of data. For the simple cases epilot brings its own tools, and you should use those first.

epilot is an excellent no-code and low-code platform. According to the epilot documentation on environments and secrets in webhooks, webhook payloads can already be reshaped inside epilot with JSONata, and environment variables can act as lookup tables for codes. For a lot of integrations that is enough.

Things change when a process runs across several systems. This comparison shows where the line usually falls.

RequirementLow-code flow in epilotDedicated mapper
Rename fields and translate values via lookup tablesgood fitnot needed
One target, one direction, one callgood fitnot needed
Add data from a database or another CRMreaches its limitsenrichment in code
Call several surrounding systems in sequencereaches its limitsflow with error handling per step
Back business rules with testslimitedvalidation with automated tests
Write the result back to epilotcumbersomewrite-back via the epilot API

Treat the table as a guide, not a hard rule. The article When is low-code in epilot no longer enough? explains why the limit is rarely epilot itself and almost always the edge of the platform.

What does the data flow of an epilot interface with Quarkus look like?

The flow starts with an event in epilot and ends with an action in a surrounding system, often followed by a write-back to epilot. In between, the mapper runs as its own service in a container.

  1. Something happens in epilot, and epilot sends a webhook to the mapper.
  2. The mapper checks that the request really comes from epilot.
  3. It converts and validates the data and fills in missing details from other sources.
  4. It calls the surrounding system via REST or triggers an event there.
  5. Where needed, it writes the result back through the epilot API so the information is available in epilot.

The epilot webhooks documentation describes the first step like this: when an event occurs, epilot sends an HTTP POST with a signed payload to the configured URL. It also notes that payloads are sent with Transfer-Encoding: chunked. A Quarkus service handles that without any extra work.

This is how I work in my current project at a grid operator in Hesse. Many processes there run outside epilot, and several third-party systems are connected through individually developed interfaces. The mapper tools for this are written in Java with Quarkus and run in containers. You can read more in the in-practice section on the home page.

How does a Quarkus service receive an epilot webhook?

A Quarkus service receives an epilot webhook through a plain REST resource. A class annotated with @Path and a method annotated with @POST are all it takes, as the Quarkus guide to writing REST services shows.

The order matters: verify first, then process. The epilot page on webhook security lists the headers webhook-id, webhook-timestamp and webhook-signature, and recommends always verifying signatures before a payload is processed.

@Path("/webhooks/epilot")
public class WebhookResource {

    @Inject
    SignatureVerifier verifier;

    @Inject
    MappingService mappingService;

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response receive(@HeaderParam("webhook-id") String messageId,
                            @HeaderParam("webhook-timestamp") String timestamp,
                            @HeaderParam("webhook-signature") String signature,
                            String rawBody) {
        if (!verifier.isValid(messageId, timestamp, signature, rawBody)) {
            return Response.status(Response.Status.UNAUTHORIZED).build();
        }
        mappingService.process(messageId, rawBody);
        return Response.ok().build();
    }
}

The body is taken as raw text on purpose, because the signature is computed over the unmodified content. Only after verification does MappingService turn the text into objects. SignatureVerifier and MappingService are classes of the project itself, not off-the-shelf libraries.

Signature checks and idempotency are covered in more depth in Processing epilot webhooks securely.

How does the mapper call surrounding systems via REST?

The mapper calls surrounding systems through a typed REST client. In Quarkus you describe the target system’s API as a Java interface, and the framework generates the implementation.

The Quarkus guide to the REST Client covers this approach, which builds on MicroProfile REST Client. The target system’s address lives in configuration, not in the code.

@RegisterRestClient(configKey = "target-system")
@Path("/customers")
public interface TargetSystemClient {

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    Response createCustomer(CustomerPayload customer);
}

The configuration then needs a single line such as quarkus.rest-client.target-system.url=${TARGET_SYSTEM_URL}. The actual address comes from an environment variable that is set differently per environment.

The same pattern works in the other direction. The mapper can serve data from surrounding systems such as other CRMs or databases to epilot via a REST API, and it can trigger events in other systems by sending a message to their interface. How such a REST API interface for epilot is put together has its own article.

Why is Quarkus a good fit for mappers in containers?

Quarkus is a good fit because it was designed for containers from the start. Services start quickly, use little memory and therefore scale out well.

What also counts for a mapper is what Quarkus ships as official extensions. That keeps your own code focused on the actual translation.

  • REST services and REST client for webhooks and calls to surrounding systems
  • health checks via SmallRye Health
  • configuration via MicroProfile Config
  • a description of the service’s own API via OpenAPI
  • fault tolerance via SmallRye Fault Tolerance
  • container images built straight from the build

The Quarkus guide to container images shows how the project becomes an image. If you need even faster startup, the guide to building a native executable explains how to compile the service natively.

For the client this means the mapper is an ordinary Java project with Maven or Gradle. Any team with Java experience can read it, build it and run it.

How does a mapper cope with errors and outages in other systems?

A mapper copes with errors through retries, timeouts and a circuit breaker. In Quarkus, annotations from SmallRye Fault Tolerance provide this, so you do not write that logic yourself.

The Quarkus guide to SmallRye Fault Tolerance covers @Retry, @Timeout, @CircuitBreaker and, as an extension, @ExponentialBackoff for growing wait times between attempts.

@ApplicationScoped
public class TargetSystemGateway {

    @Inject
    @RestClient
    TargetSystemClient client;

    @Retry(maxRetries = 4, delay = 500, jitter = 200)
    @ExponentialBackoff
    @Timeout(5000)
    @CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.5, delay = 30000)
    public void send(CustomerPayload customer) {
        client.createCustomer(customer);
    }
}

The values here are placeholders and get tuned per system. Not every error deserves a retry, though. A rejected record stays rejected no matter how often you send it, and retryOn and abortOn let you control exactly which failures trigger another attempt.

The same applies when talking to epilot. The rate limits page in the epilot documentation says the API answers with HTTP 429 once a limit is exceeded and uses the Retry-After header to state how many seconds remain until the quota resets. A mapper that writes back to epilot should respect that value.

Why does idempotency matter so much?

Idempotency makes sure a webhook delivered twice does not create a duplicate record. It matters because repeated deliveries happen on both sides.

According to the epilot documentation on webhook monitoring, any webhook event can be replayed from epilot. The documentation describes the webhook-id header as a unique message identifier, so the mapper can remember identifiers it has already processed and recognise a second delivery of the same message.

What does a mapper need to run reliably?

A mapper needs visibility, clean configuration and tests to run reliably. Without them it will still run, but nobody notices in time when it stalls.

  • Health probes: with SmallRye Health, Quarkus exposes /q/health/live and /q/health/ready, which a container platform can poll. The Quarkus guide to SmallRye Health has the details.
  • Structured logging: every run is logged with the message identifier, so a record can be traced across all systems. The Quarkus logging guide also covers JSON output.
  • Configuration and secrets outside the code: addresses, keys and signing secrets come from environment variables or a secret store. The Quarkus configuration reference explains how values are read from different sources.
  • A documented API: with the Quarkus OpenAPI extension, the mapper describes its own endpoints at /q/openapi.

On the epilot side, webhook monitoring helps. According to the documentation it shows the payload, headers and response code of each delivery, and events are kept for four weeks by default.

How are mappers tested?

Mappers are tested at two levels: the pure mapping logic with plain unit tests, and the whole service with @QuarkusTest. The Quarkus guide to testing your application shows how a test boots the application and calls endpoints with REST Assured.

Each mapping comes with sample data: an input from epilot and the expected output for the target system. When a rule changes, the tests show immediately which cases are affected.

How are mappings versioned?

Mappings are versioned like any other code, in the same repository and with a traceable history. Every rule change goes through a commit, gets tested and ships with a new version of the container.

When a surrounding system changes its format, the mapper can understand both formats for a transition period. That way a switch-over does not need a hard cut.

What monitoring, error handling and maintenance look like in day-to-day operation is described in Running epilot integrations.

Who owns the mapper’s code?

The mapper’s code belongs to you as the client. On request I hand it over to your own repository, so your team can develop and run it independently.

Alternatively, I look after operation and further development under a maintenance contract. Both options are open, and the decision is yours. The article Who owns the integration code? explains why this matters so much for grid operators.

I work alongside epilot’s consulting team, not instead of it. epilot remains your point of contact for the platform and its standard scope, and I pick up where classic development is needed. The services section on the home page lists what that covers.

How do you get started with a dedicated mapper?

You start with a free intro call in which we go through your systems and workflows. Afterwards it is clear whether epilot’s own tools are enough or whether a dedicated mapper makes sense.

  1. Intro call: free and without obligation, 30 minutes on Microsoft Teams.
  2. Individual quote: tailored to your surrounding systems, data formats and operational requirements.
  3. Delivery: the mapper is built, tested and put into operation with your systems.

Everything I offer is based on an individual quote. More answers are in the frequently asked questions on the home page, and you can pick a slot directly in the booking calendar.

Questions on this topic

What is a mapper in an epilot integration?
A mapper is a dedicated service that translates data between epilot and another system. It maps fields, converts formats, validates the data, fills in missing details from other sources and handles errors in a traceable way.
Why Quarkus rather than another Java framework?
Quarkus is built for containers, starts quickly and needs little memory. REST client, health checks, configuration, OpenAPI and fault tolerance are available as official extensions, so a mapper needs very little scaffolding of its own.
Can I not just use the payload transformation in epilot webhooks?
For simple mappings, yes. epilot webhooks offer a payload transformation based on JSONata. A dedicated mapper makes sense once several systems are involved, or data has to be enriched, checked against business rules or written back to epilot.
Who runs the mapper once it is built?
That is your call. The code belongs to you and can be handed over to your repository so your team runs it. Alternatively, I look after it under a maintenance contract.
Does a dedicated mapper replace epilot's consulting team?
No. epilot's consulting team remains your point of contact for the rollout and the standard scope. The mapper sits where data leaves the platform or comes into it.
What does building a mapper cost?
That depends on the number of surrounding systems, the data formats and your operational requirements. After the free intro call you receive an individual quote.

Does this fit your project?

In the free 30-minute intro call on Microsoft Teams we work out where epilot's standard ends for you. Afterwards you receive an individual quote.

Book a call

Published: . Last updated: .