--- name: b2c-webservices description: Implement web service integrations in B2C Commerce using LocalServiceRegistry. Use when calling external APIs, configuring service credentials in services.xml, handling HTTP requests/responses, or implementing circuit breakers. Covers HTTP, SOAP, FTP, and SFTP services. --- # Web Services Skill This skill guides you through implementing web service integrations in B2C Commerce using the Service Framework. ## Overview The Service Framework provides a structured way to call external services with: | Feature | Description | |---------|-------------| | **Configuration** | Service settings managed in Business Manager | | **Rate Limiting** | Automatic throttling to protect external systems | | **Circuit Breaker** | Automatic failure handling to prevent cascade failures | | **Logging** | Communication logging with sensitive data filtering | | **Mocking** | Test services without external calls | ## Service Types | Type | Use Case | Protocol | |------|----------|----------| | `HTTP` | REST APIs, webhooks | HTTP/HTTPS | | `HTTPForm` | Form submissions | HTTP/HTTPS with form encoding | | `FTP` | File transfers (deprecated) | FTP | | `SFTP` | Secure file transfers | SFTP | | `SOAP` | SOAP web services | HTTP/HTTPS with SOAP | | `GENERIC` | Custom protocols | Any | ## Service Framework Components ### Business Manager Configuration Services are configured in **Administration > Operations > Services**: 1. **Service Configuration** - General settings (enabled, logging, callbacks) 2. **Service Profile** - Rate limiting and circuit breaker settings 3. **Service Credential** - URL and authentication credentials ### Script Components | Component | Purpose | |-----------|---------| | `LocalServiceRegistry` | Creates service instances | | `ServiceCallback` | Defines request/response handling | | `Service` | Base service with common methods | | `Result` | Response object with status and data | ## Basic Pattern ```javascript 'use strict'; var LocalServiceRegistry = require('dw/svc/LocalServiceRegistry'); var myService = LocalServiceRegistry.createService('my.service.id', { /** * Configure the request before it is sent * @param {dw.svc.HTTPService} svc - The service instance * @param {Object} params - Parameters passed to service.call() * @returns {string} Request body */ createRequest: function (svc, params) { svc.setRequestMethod('POST'); svc.addHeader('Content-Type', 'application/json'); return JSON.stringify(params); }, /** * Parse the response after a successful call * @param {dw.svc.HTTPService} svc - The service instance * @param {dw.net.HTTPClient} client - The HTTP client with response * @returns {Object} Parsed response */ parseResponse: function (svc, client) { return JSON.parse(client.text); }, /** * Filter sensitive data from logs (required for production) * @param {string} msg - The message to filter * @returns {string} Filtered message */ filterLogMessage: function (msg) { return msg.replace(/("api_key"\s*:\s*")[^"]+"/g, '$1***"'); } }); // Call the service var result = myService.call({ key: 'value' }); if (result.ok) { var data = result.object; } else { var error = result.errorMessage; } ``` ## Service Callbacks | Callback | Required | Description | |----------|----------|-------------| | `createRequest` | Yes* | Configure request, return body | | `parseResponse` | Yes* | Parse response, return result object | | `execute` | No | Custom execution logic (replaces default) | | `initServiceClient` | No | Create/configure underlying client | | `mockCall` | No | Return mock response (execute phase only) | | `mockFull` | No | Return mock response (entire call) | | `filterLogMessage` | Recommended | Filter sensitive data from logs | | `getRequestLogMessage` | No | Custom request log message | | `getResponseLogMessage` | No | Custom response log message | *Required unless `execute` is implemented ## Result Object The `call()` method returns a `dw.svc.Result`: | Property | Type | Description | |----------|------|-------------| | `ok` | Boolean | True if successful | | `status` | String | "OK", "ERROR", or "SERVICE_UNAVAILABLE" | | `object` | Object | Response from `parseResponse` | | `error` | Number | Error code (e.g., HTTP status) | | `errorMessage` | String | Error description | | `unavailableReason` | String | Why service is unavailable | | `mockResult` | Boolean | True if from mock callback | ### Unavailable Reasons | Reason | Description | |--------|-------------| | `TIMEOUT` | Call timed out | | `RATE_LIMITED` | Rate limit exceeded | | `CIRCUIT_BROKEN` | Circuit breaker open | | `DISABLED` | Service disabled | | `CONFIG_PROBLEM` | Configuration error | ## Error Handling ```javascript var result = myService.call(params); if (result.ok) { return result.object; } // Handle different error types switch (result.status) { case 'SERVICE_UNAVAILABLE': switch (result.unavailableReason) { case 'RATE_LIMITED': // Retry later break; case 'CIRCUIT_BROKEN': // Service is down, use fallback break; case 'TIMEOUT': // Request timed out break; } break; case 'ERROR': // Check HTTP status code if (result.error === 401) { // Authentication error } else if (result.error === 404) { // Resource not found } break; } throw new Error('Service error: ' + result.errorMessage); ``` ## Log Filtering Production environments require log filtering to prevent sensitive data exposure: ```javascript var myService = LocalServiceRegistry.createService('my.service', { createRequest: function (svc, params) { // ... configure request }, parseResponse: function (svc, client) { return JSON.parse(client.text); }, /** * Filter sensitive data from all log messages */ filterLogMessage: function (msg) { // Filter API keys msg = msg.replace(/api_key=[^&]+/g, 'api_key=***'); // Filter authorization headers msg = msg.replace(/Authorization:\s*[^\r\n]+/gi, 'Authorization: ***'); // Filter passwords in JSON msg = msg.replace(/("password"\s*:\s*")[^"]+"/g, '$1***"'); return msg; }, /** * Custom request log message (optional) */ getRequestLogMessage: function (request) { // Return custom message or null for default return 'Request: ' + request.substring(0, 100) + '...'; }, /** * Custom response log message (optional) */ getResponseLogMessage: function (response) { // Return custom message or null for default return 'Response received'; } }); ``` ## Mocking Services Use mock callbacks for testing without external calls: ```javascript var myService = LocalServiceRegistry.createService('my.service', { createRequest: function (svc, params) { svc.setRequestMethod('GET'); svc.addParam('id', params.id); return null; }, parseResponse: function (svc, client) { return JSON.parse(client.text); }, /** * Mock the execute phase only (createRequest and parseResponse still run) */ mockCall: function (svc, request) { return { statusCode: 200, text: JSON.stringify({ id: 1, name: 'Mock Data' }) }; }, /** * Or mock the entire call (replaces all phases) */ mockFull: function (svc, params) { return { id: params.id, name: 'Full Mock Data' }; } }); // Force mock mode myService.setMock(); var result = myService.call({ id: 123 }); ``` ## Service Configuration in Business Manager ### Creating a Service 1. Go to **Administration > Operations > Services** 2. Click **New** under Service Configurations 3. Fill in: - **Service ID**: Unique identifier (e.g., `my.api.service`) - **Service Type**: HTTP, FTP, SOAP, etc. - **Enabled**: Check to enable - **Profile**: Select or create a profile - **Credential**: Select or create credentials - **Communication Log**: Enable for debugging ### Service Profile Settings | Setting | Description | |---------|-------------| | **Timeout** | Maximum wait time in milliseconds | | **Rate Limit** | Maximum calls per time unit | | **Circuit Breaker Enabled** | Enable automatic failure handling | | **Max Circuit Breaker Calls** | Calls before circuit opens | | **Circuit Breaker Interval** | Time window for tracking failures | ### Service Credential Settings | Setting | Description | |---------|-------------| | **ID** | Credential identifier | | **URL** | Base URL for the service | | **User** | Username for authentication | | **Password** | Password for authentication | ## Detailed References - [HTTP Services](references/HTTP-SERVICES.md) - REST API integrations - [FTP/SFTP Services](references/FTP-SERVICES.md) - File transfer operations - [SOAP Services](references/SOAP-SERVICES.md) - SOAP web service integrations - [Services XML](references/SERVICES-XML.md) - Import/export service configurations ## Script API Classes | Class | Description | |-------|-------------| | `dw.svc.LocalServiceRegistry` | Create service instances | | `dw.svc.Service` | Base service class | | `dw.svc.HTTPService` | HTTP service methods | | `dw.svc.FTPService` | FTP/SFTP service methods | | `dw.svc.SOAPService` | SOAP service methods | | `dw.svc.Result` | Service call result | | `dw.svc.ServiceConfig` | Service configuration | | `dw.svc.ServiceProfile` | Rate limit/circuit breaker config | | `dw.svc.ServiceCredential` | Authentication credentials | | `dw.net.HTTPClient` | Underlying HTTP client | | `dw.net.FTPClient` | Underlying FTP client | | `dw.net.SFTPClient` | Underlying SFTP client |