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']");