PHP

Map Complex API Response to PHP Model

Transform a complex, potentially inconsistent external API response into a clean, application-specific PHP data transfer object (DTO) or model.

<?php

class ProductDTO
{
    public readonly string $id;
    public readonly string $name;
    public readonly float $price;
    public readonly ?string $currency;
    public readonly array $tags;
    public readonly ?string $description;

    public function __construct(string $id, string $name, float $price, ?string $currency = null, array $tags = [], ?string $description = null)
    {
        $this->id = $id;
        $this->name = $name;
        $this->price = $price;
        $this->currency = $currency;
        $this->tags = $tags;
        $this->description = $description;
    }

    /**
     * Creates a ProductDTO from a raw API response array.
     * Handles varying key names and missing fields.
     */
    public static function fromApiResponse(array $apiResponse): self
    {
        // Define mappings for common API key variations
        $idKeys = ['product_id', 'id', 'productId', 'identifier'];
        $nameKeys = ['product_name', 'name', 'title'];
        $priceKeys = ['unit_price', 'price', 'cost'];
        $currencyKeys = ['currency', 'currency_code', 'currencyCode'];
        $tagsKeys = ['tags', 'categories', 'keywords'];
        $descriptionKeys = ['description', 'long_description', 'product_description'];

        $getScalarValue = function(array $data, array $keys, $default = null) {
            foreach ($keys as $key) {
                if (isset($data[$key]) && !is_array($data[$key])) {
                    return $data[$key];
                }
            }
            return $default;
        };

        $getArrayValue = function(array $data, array $keys, array $default = []) {
            foreach ($keys as $key) {
                if (isset($data[$key]) && is_array($data[$key])) {
                    return $data[$key];
                }
            }
            return $default;
        };

        $id = (string) $getScalarValue($apiResponse, $idKeys) ?: throw new InvalidArgumentException('Product ID is missing or invalid.');
        $name = (string) $getScalarValue($apiResponse, $nameKeys) ?: throw new InvalidArgumentException('Product name is missing or invalid.');
        $price = (float) $getScalarValue($apiResponse, $priceKeys, 0.0);
        $currency = (string) $getScalarValue($apiResponse, $currencyKeys) ?? null;
        $tags = $getArrayValue($apiResponse, $tagsKeys);
        $description = (string) $getScalarValue($apiResponse, $descriptionKeys) ?? null;

        return new self($id, $name, $price, $currency, $tags, $description);
    }
}

// Example Usage:
// $rawApiResponse1 = [
//     'product_id' => 'SKU123',
//     'name' => 'Premium Widget',
//     'unit_price' => 29.99,
//     'currency' => 'USD',
//     'categories' => ['gadget', 'home'],
//     'long_description' => 'A high-quality widget for various uses.'
// ];

// $rawApiResponse2 = [
//     'id' => 'SKU456',
//     'title' => 'Basic Gizmo',
//     'price' => 9.99,
//     'tags' => ['tool'],
// ];

// try {
//     $product1 = ProductDTO::fromApiResponse($rawApiResponse1);
//     echo 'Product 1: ' . $product1->name . ' - ' . $product1->price . "
";
    // var_dump($product1);

//     $product2 = ProductDTO::fromApiResponse($rawApiResponse2);
//     echo 'Product 2: ' . $product2->name . ' - ' . $product2->price . "
";
    // var_dump($product2);

// } catch (InvalidArgumentException $e) {
//     echo 'Error: ' . $e->getMessage() . "
";
// }

?>
How it works: This PHP snippet demonstrates how to map a potentially complex or inconsistent API response into a clean, application-specific Data Transfer Object (DTO). The `ProductDTO` class defines a strict structure for product data within your application. The static `fromApiResponse` factory method intelligently extracts and normalizes values from a raw API array, handling different key names, missing optional fields, and ensuring correct data types. This pattern significantly improves code readability, maintainability, and type safety when integrating with diverse external APIs.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs