Structural Complexity: Low

Adapter Pattern

Convert the interface of a class into another interface clients expect.

The Problem

In an e-commerce platform, you need to integrate with multiple third-party payment gateways — Stripe and PayPal — each with its own proprietary API. Stripe expects amounts in cents and returns a status field, while PayPal expects amounts as formatted strings and returns a state field. Without an abstraction layer, your application code becomes tightly coupled to each gateway’s specific API.

The Solution

The Adapter pattern wraps each third-party API behind a common PaymentGateway interface. Each adapter translates calls from the unified interface into the format expected by the specific API. The application code only interacts with the PaymentGateway interface, remaining unaware of the differences under the hood.

Structure

  • Target Interface (PaymentGateway) — Defines the uniform charge(amount, currency) method.
  • Adaptees (StripeApi, PayPalApi) — The existing third-party classes with incompatible interfaces.
  • Adapters (StripeAdapter, PayPalAdapter) — Implement PaymentGateway and internally delegate to their respective adaptee, translating parameters and return values.
  • Client (AdapterController) — Uses only the PaymentGateway interface, selecting the appropriate adapter at runtime.

Implementation

The StripeApi class simulates Stripe’s API, which expects amounts in cents and returns a charge object. The PayPalApi class simulates PayPal’s API, which expects a string total and returns a different result structure.

The StripeAdapter converts dollars to cents before calling StripeApi.createCharge(), then maps the result to a PaymentResult. The PayPalAdapter formats the amount as a fixed-decimal string before calling PayPalApi.makePayment().

export interface PaymentResult {
  success: boolean;
  transactionId: string;
  gateway: string;
}

export interface PaymentGateway {
  charge(amount: number, currency: string): PaymentResult;
}

NestJS Integration

Each adaptee and each adapter is registered as a NestJS @Injectable() provider. The adapters receive their adaptees via constructor injection, which NestJS resolves automatically. The module exports the adapters so other modules can depend on the PaymentGateway interface without knowing about the underlying APIs.

When to Use

  • You need to integrate third-party libraries or services whose interfaces do not match your application’s expected interface.
  • You want to decouple your business logic from specific external API implementations.
  • You are consolidating multiple legacy systems that expose different APIs.
  • You want to write tests against an interface rather than a concrete external dependency.

When NOT to Use

  • The external API already matches your expected interface.
  • You control both the client and the service code and can refactor directly.
  • The differences between APIs are so extensive that an adapter becomes a full translation layer.