How to Build a Frontend Anti‑Corruption Layer with RxJS to Shield Against API Changes

This article explains why B2B front‑end applications suffer from frequent API changes, introduces the anti‑corruption layer concept adapted from HAL and DDD, and demonstrates how to implement a robust, RxJS‑based layer that isolates UI code from evolving back‑end contracts while offering caching, fallback, and testing benefits.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
How to Build a Frontend Anti‑Corruption Layer with RxJS to Shield Against API Changes

1. Problem and Challenges

In long‑lived B2B products, the front‑end depends heavily on back‑end APIs. Over years of iteration, any change in an API (field adjustments, call‑method changes, or multiple version coexistence) can break components such as a dashboard that displays memory metrics. The front‑end often acts as a downstream client in a supplier relationship, unable to influence the upstream API design, which leads to costly refactoring when interfaces evolve.

2. Anti‑Corruption Layer Design

The Hardware Abstraction Layer (HAL) concept, later adopted as the Anticorruption Layer in Domain‑Driven Design, isolates downstream models from upstream changes. Applying this to the browser, RxJS Observables provide a non‑intrusive way to build a front‑end anti‑corruption layer that shields UI components from API volatility. Unlike GraphQL or BFF solutions, a browser‑side layer avoids extra deployment and operational overhead.

3. Implementation

Core observable utilities are created to wrap API calls:

export function getMemoryFreeObservable(): Observable<number> {
  return fromFetch("/api/v1/memory/free").pipe(mergeMap(res => res.json()));
}

export function getMemoryUsageObservable(): Observable<number> {
  return fromFetch("/api/v1/memory/usage").pipe(mergeMap(res => res.json()));
}

export function getMemoryUsagePercent(): Promise<number> {
  return lastValueFrom(
    forkJoin([getMemoryFreeObservable(), getMemoryUsageObservable()]).pipe(
      map(([free, usage]) => +((usage / (usage + free)) * 100).toFixed(2))
    )
  );
}

export function getMemoryFree(): Promise<number> {
  return lastValueFrom(getMemoryFreeObservable());
}

export function getMemoryUsage(): Promise<number> {
  return lastValueFrom(getMemoryUsageObservable());
}

A React component consumes the percentage via the anti‑corruption layer:

function MemoryUsagePercent() {
  const [usage, setUsage] = useState(0);
  useEffect(() => {
    (async () => {
      const result = await getMemoryUsagePercent();
      setUsage(result);
    })();
  }, []);
  return <div>Usage: {usage} %</div>;
}
export default MemoryUsagePercent;

When API fields change, only the observable mapping needs adjustment, leaving component code untouched. For call‑method changes or version coexistence, higher‑order observables combine lower‑level streams, and the race operator selects the first available version:

export function getMemoryObservable(): Observable<{free:number; usage:number}> {
  const legacy = getMemoryLegacyObservable();
  const current = fromFetch("/api/v3/memory").pipe(mergeMap(res => res.json()), map(data => data.data));
  return race(legacy, current);
}

4. Additional Applications

Concept mapping – the layer translates raw API data into domain‑specific terms.

Format adaptation – it reshapes responses to match UI expectations.

Caching – a simple in‑memory cache reduces request pressure.

Stability fallback – catchError can provide default values when all versions fail.

Integration testing – mock data can be returned directly from the layer, enabling fast UI tests.

class CacheService {
  private cache: {[key:string]:any} = {};
  getData() {
    if (this.cache) {
      return of(this.cache);
    } else {
      return fromFetch("/api/v3/memory").pipe(
        mergeMap(res => res.json()),
        map(data => data.data),
        tap(data => { this.cache = data; })
      );
    }
  }
}

5. Summary

Why front‑end code suffers from frequent API changes in B2B scenarios.

The anti‑corruption layer concept and why RxJS is a suitable implementation.

Concrete Observable‑based code that isolates UI components from API contracts.

Extra benefits such as concept mapping, format adaptation, caching, fallback, and testing support.

Introduce the layer only when the front‑end is a downstream consumer of many unstable APIs; otherwise the added complexity may outweigh the benefits.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

frontendJavaScriptrxjsAnti‑Corruption LayerobservableAPI stability
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.