Table of Contents
Need to transform data between two different API formats? Implement both interfaces in a single service class. This pattern creates a bridge that speaks both languages.
The Problem
You’re building a mobile app that expects data in Format A (clean REST), but your data source provides Format B (legacy XML-RPC or a different REST structure). You need to translate between them without rewriting either side.
The Solution: Dual Interface Implementation
Create a transformer service that implements both interfaces:
<?php
namespace App\Services;
use App\Contracts\SourceApiInterface; // What you're fetching from
use App\Contracts\TargetApiInterface; // What clients expect
class DataTransformer implements SourceApiInterface, TargetApiInterface
{
private HttpClient $client;
public function __construct(HttpClient $client)
{
$this->client = $client;
}
// ===================================================
// SOURCE API METHODS (fetch from external API)
// ===================================================
public function fetchProducts(array $filters): array
{
// Fetch from external API
$response = $this->client->get('/v1/items', $filters);
return $response->json();
}
public function fetchCategories(): array
{
$response = $this->client->get('/v1/taxonomies');
return $response->json();
}
// ===================================================
// TARGET API METHODS (transform + expose to clients)
// ===================================================
public function getItems(string $category, int $limit = 20): array
{
// Map category to source filter
$sourceFilters = ['taxonomy_id' => $this->mapCategory($category)];
// Fetch using source API method
$sourceData = $this->fetchProducts($sourceFilters);
// Transform to target format
return $this->transformToItems($sourceData);
}
public function getItemDetails(string $id): array
{
$sourceData = $this->fetchProduct($id);
return $this->transformToItemDetails($sourceData);
}
// ===================================================
// PRIVATE TRANSFORMATION LOGIC
// ===================================================
private function transformToItems(array $sourceProducts): array
{
return array_map(function ($product) {
return [
'id' => $product['item_id'],
'title' => $product['name'],
'price' => $product['cost'] / 100, // cents to dollars
'stock' => $product['inventory']['available'],
];
}, $sourceProducts);
}
private function mapCategory(string $targetCategory): int
{
// Map client-facing category names to source taxonomy IDs
return match($targetCategory) {
'electronics' => 15,
'books' => 8,
'clothing' => 23,
default => 1,
};
}
}
How It Works
- Source interface methods (
fetchProducts,fetchCategories) handle raw API calls to the external service - Target interface methods (
getItems,getItemDetails) expose the clean API your clients expect - Transformation happens in private methods that map fields, rename keys, convert units, etc.
The transformer becomes a bidirectional adapter β it speaks the source API internally and the target API publicly.
When to Use This Pattern
- Wrapping legacy APIs with modern REST interfaces
- Multi-source data aggregation where you combine APIs into one unified interface
- API versioning β v2 interface transforms data from v1 endpoints
- SDK replacement β your app expects Reddit API format, but you’re pulling from WordPress
Benefits
Type safety: Both interfaces enforce contracts at compile time
Testability: Mock either interface independently
Single responsibility: One class, one job β transform between two formats
Swappability: Replace the source API without changing client code (dependency inversion)
Real-World Example
A mobile app needed a Reddit-style API (posts, comments, upvotes) but the content lived in WordPress. The transformer implemented both WordPressApiInterface and RedditApiInterface:
fetchPosts()called WordPress REST APIgetHot()transformed WP posts into Reddit listing format- Mobile app saw clean Reddit JSON, never touched WordPress directly
Key insight: When formats overlap, the target format wins. The transformer hides complexity from clients.
Leave a Reply