← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Gateway Pattern

quality Intermediate

Also Known As

service gateway API wrapper external service adapter

TL;DR

A class that encapsulates access to an external system or resource — wrapping HTTP APIs, queues, or legacy systems behind a clean interface that the rest of the application uses.

Explanation

A Gateway (Martin Fowler, PoEAA) isolates external dependencies behind an interface. PaymentGateway, EmailGateway, SMSGateway — each wraps one external system. Benefits: the application code never calls the HTTP client or SDK directly; the gateway can be mocked in tests; switching providers means only changing the gateway implementation. Similar to Adapter but typically wraps external systems rather than incompatible interfaces. Distinguished from Repository (data storage) by focusing on external service calls.

Common Misconception

Gateways and adapters are the same — both wrap external interfaces, but a Gateway specifically wraps access to external systems (APIs, queues); an Adapter translates between two existing interfaces.

Why It Matters

Without a gateway, Stripe's SDK is called directly throughout the codebase — switching to Braintree requires hunting down every Stripe call; with a gateway, only one class changes.

Common Mistakes

  • Gateway that leaks provider-specific exceptions — wrap them in domain exceptions.
  • Fat gateway with too much logic — gateways translate calls, not implement business rules.
  • Not defining a gateway interface — without an interface, mocking in tests requires more work.
  • One giant ExternalServiceGateway — one gateway per external system.

Code Examples

✗ Vulnerable
// No gateway — Stripe SDK scattered everywhere:
class OrderService {
    public function charge(Order $order): void {
        $stripe = new \Stripe\StripeClient(getenv('STRIPE_KEY'));
        $charge = $stripe->charges->create([
            'amount'   => $order->total->cents(),
            'currency' => 'gbp',
            'source'   => $order->paymentToken,
        ]);
        // Stripe-specific code in domain service
    }
}
✓ Fixed
// Gateway isolates the provider:
interface PaymentGateway {
    public function charge(Money $amount, string $token): PaymentResult;
}

class StripeGateway implements PaymentGateway {
    public function charge(Money $amount, string $token): PaymentResult {
        $charge = $this->stripe->charges->create([...]);
        return new PaymentResult($charge->id, $charge->status);
    }
}

// Domain service depends on interface:
class OrderService {
    public function __construct(private PaymentGateway $payments) {}
    public function charge(Order $order): void {
        $result = $this->payments->charge($order->total, $order->token);
    }
}

Added 16 Mar 2026
Edited 22 Mar 2026
Views 20
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Amazonbot 6 Perplexity 4 Google 2 Unknown AI 2 Majestic 1 Ahrefs 1
crawler 15 crawler_json 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Create a Gateway class as the single entry point to an external system — all HTTP calls, data mapping, and error handling live in the gateway, keeping your domain code clean
📦 Applies To
any web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Direct Guzzle or cURL calls scattered across service classes; external API error handling duplicated in multiple places; no single abstraction for a third-party service
Auto-detectable: ✗ No phpstan deptrac
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class Tests: Update

✓ schema.org compliant