From 10dfd5fb09dc7eef51b3d0deee8e4b315dc7a2a4 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 5 Nov 2025 15:05:09 +0000 Subject: [PATCH] [POLISH] ADD SDK info LRN-48967 --- docs/quickstart/analytics/data-api-demo.php | 298 ++++++++++++++++++++ docs/quickstart/index.html | 4 + src/Request/Init.php | 3 +- src/Request/Remote.php | 9 + tests/Request/InitTest.php | 78 +++++ tests/Request/RemoteTest.php | 11 +- 6 files changed, 400 insertions(+), 3 deletions(-) create mode 100644 docs/quickstart/analytics/data-api-demo.php diff --git a/docs/quickstart/analytics/data-api-demo.php b/docs/quickstart/analytics/data-api-demo.php new file mode 100644 index 0000000..c9cf977 --- /dev/null +++ b/docs/quickstart/analytics/data-api-demo.php @@ -0,0 +1,298 @@ + $consumerKey, + 'domain' => 'localhost' +]; + +// Request packet +$requestPacket = [ + 'limit' => 3 +]; + +// Make the Data API request +$dataApi = new DataApi(); +$response = $dataApi->request( + $endpoint, + $securityPacket, + $consumerSecret, + $requestPacket, + $action +); + +// Get response data +$statusCode = $response->getStatusCode(); +$responseBody = $response->getBody(); + +// Extract metadata from the request packet to show what headers were sent +// The SDK automatically adds metadata to the request packet +$init = new Init('data', $securityPacket, $consumerSecret, $requestPacket, $action, null, null, $endpoint); +$generatedRequest = $init->generate(); +$decodedRequest = json_decode($generatedRequest['request'], true); +$metadata = $decodedRequest['meta'] ?? []; + +// Extract the metadata values that are sent as headers +$consumerHeader = $metadata['consumer'] ?? 'N/A'; +$actionHeader = $metadata['action'] ?? 'N/A'; +$sdkVersion = $metadata['sdk']['version'] ?? 'unknown'; +$sdkLang = $metadata['sdk']['lang'] ?? 'unknown'; +$sdkHeader = isset($metadata['sdk']['lang']) && isset($metadata['sdk']['version']) + ? strtoupper($metadata['sdk']['lang']) . ':' . ltrim($metadata['sdk']['version'], 'v') + : 'N/A'; + +// Format response body for display +$formattedResponse = json_encode(json_decode($responseBody), JSON_PRETTY_PRINT); + +?> + + + + + + Data API Demo - Metadata Headers + + + + +

Data API Demo - Metadata Headers

+

This page demonstrates the metadata headers that are automatically included in every Data API request.

+ + +
+
+

Request Information

+
+
+ + + + + + + + + + + + + + + +
Endpoint
Action
Status Code + + + +
+
+
+ + +
+
+

Metadata Headers (Sent Automatically)

+
+
+

These headers are added automatically by the SDK and are invisible to customers:

+ + + + + + + + + + + + + + + + + + + + + +
Header NameHeader Value
X-Learnosity-Consumer
X-Learnosity-Action
X-Learnosity-SDK
+
+ Metadata Format: +
    +
  • Consumer: The consumer key from the security packet
  • +
  • Action: Format is {method}_{endpoint} (e.g., )
  • +
  • SDK: Format is {language}:{version} (e.g., )
  • +
+
+
+ SDK Metadata (in request packet): +
    +
  • Version:
  • +
  • Language:
  • +
  • Language Version:
  • +
  • Platform:
  • +
+
+
+
+ + +
+
+

Response Body

+
+
+
+
+
+ + +
+

How It Works

+ +
+ + + diff --git a/docs/quickstart/index.html b/docs/quickstart/index.html index 3e0f521..30b97e6 100644 --- a/docs/quickstart/index.html +++ b/docs/quickstart/index.html @@ -44,6 +44,10 @@

Analytics examples

  • Paginated data extraction

    Example of how to work with large datasets in Data API that return paginated results. Learn more.

    +
  • +
  • + Data API metadata headers +

    Demonstrates the metadata headers that are automatically included in every Data API request by the SDK.

  • diff --git a/src/Request/Init.php b/src/Request/Init.php index 4174cef..022349d 100644 --- a/src/Request/Init.php +++ b/src/Request/Init.php @@ -261,7 +261,8 @@ private function deriveAction(): string // Remove version information from the path // (e.g., /v2023.1.lts/itembank/items -> /itembank/items, /v1/sessions -> /sessions, /developer/items -> /items) - $path = preg_replace('/\/(v\d+(\.\d+)*(\.[a-zA-Z]+)?|latest(-lts)?|developer)/', '', $path); + // Supports: v1, v1.85.0, v2023.1.lts, v2025.3.LTS, v2022.3.preview1, latest, latest-lts, developer + $path = preg_replace('/\/(v\d+(\.\d+)*(\.[a-zA-Z0-9]+)?|latest(-lts)?|developer)/', '', $path); // Ensure path starts with / if (!empty($path) && $path[0] !== '/') { diff --git a/src/Request/Remote.php b/src/Request/Remote.php index 731849e..531d62f 100644 --- a/src/Request/Remote.php +++ b/src/Request/Remote.php @@ -140,6 +140,15 @@ private function addMetadataHeaders(array $headers, array $post): array if (isset($meta['action'])) { $headers[] = 'X-Learnosity-Action: ' . $meta['action']; } + + // Add SDK header if available (format: language:version, e.g., "PHP:1.1.0") + if (isset($meta['sdk']['lang']) && isset($meta['sdk']['version'])) { + $lang = strtoupper($meta['sdk']['lang']); + $version = $meta['sdk']['version']; + // Remove 'v' prefix if present + $version = ltrim($version, 'v'); + $headers[] = 'X-Learnosity-SDK: ' . $lang . ':' . $version; + } } catch (Exception $e) { // Silently ignore JSON decode errors to avoid breaking requests } diff --git a/tests/Request/InitTest.php b/tests/Request/InitTest.php index c2eedfa..81c380a 100644 --- a/tests/Request/InitTest.php +++ b/tests/Request/InitTest.php @@ -307,6 +307,84 @@ public function testDataApiActionMetadata() 'endpoint' => 'https://data.learnosity.com/v2023.1.lts/session_scores', 'action' => null, // should default to 'get' 'expected' => 'get_/session_scores' + ], + // Test uppercase LTS + [ + 'endpoint' => 'https://data.learnosity.com/v2025.3.LTS/itembank/items', + 'action' => 'get', + 'expected' => 'get_/itembank/items' + ], + // Test v2025.2.LTS + [ + 'endpoint' => 'https://data.learnosity.com/v2025.2.LTS/sessions', + 'action' => 'get', + 'expected' => 'get_/sessions' + ], + // Test simple v1 + [ + 'endpoint' => 'https://data.learnosity.com/v1/items', + 'action' => 'get', + 'expected' => 'get_/items' + ], + // Test v1.85.0 + [ + 'endpoint' => 'https://data.learnosity.com/v1.85.0/itembank/items', + 'action' => 'get', + 'expected' => 'get_/itembank/items' + ], + // Test latest + [ + 'endpoint' => 'https://data.learnosity.com/latest/itembank/items', + 'action' => 'get', + 'expected' => 'get_/itembank/items' + ], + // Test latest-lts + [ + 'endpoint' => 'https://data.learnosity.com/latest-lts/sessions', + 'action' => 'get', + 'expected' => 'get_/sessions' + ], + // Test developer + [ + 'endpoint' => 'https://data.learnosity.com/developer/items', + 'action' => 'get', + 'expected' => 'get_/items' + ], + // Test preview1 (alphanumeric suffix) + [ + 'endpoint' => 'https://data.learnosity.com/v2022.3.preview1/items', + 'action' => 'get', + 'expected' => 'get_/items' + ], + // Test preview2 + [ + 'endpoint' => 'https://data.learnosity.com/v2022.2.preview2/sessions', + 'action' => 'get', + 'expected' => 'get_/sessions' + ], + // Test beta2 + [ + 'endpoint' => 'https://data.learnosity.com/v1.2.3.beta2/test', + 'action' => 'get', + 'expected' => 'get_/test' + ], + // Test alpha1 + [ + 'endpoint' => 'https://data.learnosity.com/v2024.1.alpha1/items', + 'action' => 'get', + 'expected' => 'get_/items' + ], + // Test URL with no version + [ + 'endpoint' => 'https://data.learnosity.com/items', + 'action' => 'get', + 'expected' => 'get_/items' + ], + // Test false positive: path starting with 'v' but not a version + [ + 'endpoint' => 'https://data.learnosity.com/validate/items', + 'action' => 'get', + 'expected' => 'get_/validate/items' ] ]; diff --git a/tests/Request/RemoteTest.php b/tests/Request/RemoteTest.php index a31a626..261b7e7 100644 --- a/tests/Request/RemoteTest.php +++ b/tests/Request/RemoteTest.php @@ -48,7 +48,7 @@ public function testMetadataHeadersAddedToDataApiRequests() // Create Data API request data with metadata $requestData = [ 'security' => '{"consumer_key":"test_consumer","domain":"localhost"}', - 'request' => '{"meta":{"sdk":{"version":"test"},"consumer":"test_consumer","action":"get_/itembank/items"},"limit":100}', + 'request' => '{"meta":{"sdk":{"version":"v1.1.0","lang":"php"},"consumer":"test_consumer","action":"get_/itembank/items"},"limit":100}', 'action' => 'get' ]; @@ -58,6 +58,7 @@ public function testMetadataHeadersAddedToDataApiRequests() // Verify that metadata headers were added $consumerHeaderFound = false; $actionHeaderFound = false; + $sdkHeaderFound = false; foreach ($result as $header) { if (strpos($header, 'X-Learnosity-Consumer: test_consumer') === 0) { @@ -66,10 +67,14 @@ public function testMetadataHeadersAddedToDataApiRequests() if (strpos($header, 'X-Learnosity-Action: get_/itembank/items') === 0) { $actionHeaderFound = true; } + if (strpos($header, 'X-Learnosity-SDK: PHP:1.1.0') === 0) { + $sdkHeaderFound = true; + } } $this->assertTrue($consumerHeaderFound, 'Consumer header should be added'); $this->assertTrue($actionHeaderFound, 'Action header should be added'); + $this->assertTrue($sdkHeaderFound, 'SDK header should be added'); } /** @@ -92,7 +97,9 @@ public function testMetadataHeadersNotAddedToNonDataApiRequests() // Verify that no metadata headers were added $hasMetadataHeaders = false; foreach ($result as $header) { - if (strpos($header, 'X-Learnosity-Consumer:') !== false || strpos($header, 'X-Learnosity-Action:') !== false) { + if (strpos($header, 'X-Learnosity-Consumer:') !== false + || strpos($header, 'X-Learnosity-Action:') !== false + || strpos($header, 'X-Learnosity-SDK:') !== false) { $hasMetadataHeaders = true; break; }