Skip to main content
Version: 2026.1

ResponseMappingService

The ResponseMappingService provides a flexible way to extract values from JSON API responses using Symfony Expression Language. This service addresses the problem of inconsistent response structures across different model endpoints.

Overview

Different API endpoints often return data in varying formats. Instead of hardcoding response parsing logic for each endpoint, the ResponseMappingService allows you to configure how to extract values using expressions.

Basic Usage

use Pimcore\Bundle\CopilotBundle\Service\ResponseMappingServiceInterface;

/** @var ResponseMappingServiceInterface $responseMappingService */

// Simple property extraction
$jsonResponse = '{"content": "Image description foo bar"}';
$result = $responseMappingService->mapResponse($jsonResponse, "response['content']");
// Result: "Image description foo bar"

// Nested array access
$jsonResponse = '[{"translation_text": "Hello world"}]';
$result = $responseMappingService->mapResponse($jsonResponse, "response[0]['translation_text']");
// Result: "Hello world"

Configuration Examples

Image Description Endpoint

For an endpoint that returns:

{
"content": "A beautiful sunset over the mountains"
}

Configuration:

image_description: response['content']

If the API changes to use a different key:

{
"description": "A beautiful sunset over the mountains"
}

Simply update the configuration:

image_description: response['description']

Translation Endpoint

For HuggingFace translation responses:

[{"translation_text": "Bonjour le monde"}]

Configuration:

translated_text: response[0]['translation_text']

Complex Nested Responses

For responses with nested structures:

{
"data": {
"results": [
{"label": "positive", "score": 0.95}
]
}
}

Configuration:

classification_label: response['data']['results'][0]['label']
classification_score: response['data']['results'][0]['score']

Advanced Features

Fallback Values

Use the null coalescing operator for fallback values:

description: response['content'] ?? response['description'] ?? 'No description available'

Conditional Logic

Extract different values based on conditions:

result: response['status'] == 'success' ? response['message'] : response['error']

String Manipulation

Concatenate or modify extracted values:

full_description: 'Description: ' ~ response['content']

Additional Variables

Pass additional variables for use in expressions:

$additionalVariables = ['prefix' => 'Result: '];
$result = $responseMappingService->mapResponse(
$jsonResponse,
"prefix ~ response['content']",
$additionalVariables
);

Security

The service maintains security by disabling the constant function to prevent exposure of internal system information, similar to other expression services in the bundle.

Use Cases

  • Multi-provider integrations: Support different AI/ML providers with varying response formats
  • API versioning: Adapt to changes in API response structures without code changes
  • Configuration-driven responses: Allow end users to configure response mapping
  • Complex data extraction: Handle nested objects, arrays, and conditional logic

Real-World Examples

Extracting Image Descriptions

// Provider A format
$responseA = '{"description": "A cat sitting on a windowsill"}';
$configA = "response['description']";

// Provider B format
$responseB = '{"result": {"text": "A cat sitting on a windowsill"}}';
$configB = "response['result']['text']";

// Both can be handled with the same service, different expressions
$descriptionA = $responseMappingService->mapResponse($responseA, $configA);
$descriptionB = $responseMappingService->mapResponse($responseB, $configB);

Handling Classification Results

// Format 1: Separate arrays
$response1 = '{"labels": ["positive", "negative"], "scores": [0.95, 0.05]}';
$bestLabel1 = $responseMappingService->mapResponse($response1, "response['labels'][0]");

// Format 2: Array of objects
$response2 = '[{"label": "positive", "score": 0.95}, {"label": "negative", "score": 0.05}]';
$bestLabel2 = $responseMappingService->mapResponse($response2, "response[0]['label']");