|
| 1 | +--- |
| 2 | +name: b2c-webservices |
| 3 | +description: Guide for implementing web service integrations in Salesforce B2C Commerce |
| 4 | +--- |
| 5 | + |
| 6 | +# Web Services Skill |
| 7 | + |
| 8 | +This skill guides you through implementing web service integrations in B2C Commerce using the Service Framework. |
| 9 | + |
| 10 | +## Overview |
| 11 | + |
| 12 | +The Service Framework provides a structured way to call external services with: |
| 13 | + |
| 14 | +| Feature | Description | |
| 15 | +|---------|-------------| |
| 16 | +| **Configuration** | Service settings managed in Business Manager | |
| 17 | +| **Rate Limiting** | Automatic throttling to protect external systems | |
| 18 | +| **Circuit Breaker** | Automatic failure handling to prevent cascade failures | |
| 19 | +| **Logging** | Communication logging with sensitive data filtering | |
| 20 | +| **Mocking** | Test services without external calls | |
| 21 | + |
| 22 | +## Service Types |
| 23 | + |
| 24 | +| Type | Use Case | Protocol | |
| 25 | +|------|----------|----------| |
| 26 | +| `HTTP` | REST APIs, webhooks | HTTP/HTTPS | |
| 27 | +| `HTTPForm` | Form submissions | HTTP/HTTPS with form encoding | |
| 28 | +| `FTP` | File transfers (deprecated) | FTP | |
| 29 | +| `SFTP` | Secure file transfers | SFTP | |
| 30 | +| `SOAP` | SOAP web services | HTTP/HTTPS with SOAP | |
| 31 | +| `GENERIC` | Custom protocols | Any | |
| 32 | + |
| 33 | +## Service Framework Components |
| 34 | + |
| 35 | +### Business Manager Configuration |
| 36 | + |
| 37 | +Services are configured in **Administration > Operations > Services**: |
| 38 | + |
| 39 | +1. **Service Configuration** - General settings (enabled, logging, callbacks) |
| 40 | +2. **Service Profile** - Rate limiting and circuit breaker settings |
| 41 | +3. **Service Credential** - URL and authentication credentials |
| 42 | + |
| 43 | +### Script Components |
| 44 | + |
| 45 | +| Component | Purpose | |
| 46 | +|-----------|---------| |
| 47 | +| `LocalServiceRegistry` | Creates service instances | |
| 48 | +| `ServiceCallback` | Defines request/response handling | |
| 49 | +| `Service` | Base service with common methods | |
| 50 | +| `Result` | Response object with status and data | |
| 51 | + |
| 52 | +## Basic Pattern |
| 53 | + |
| 54 | +```javascript |
| 55 | +'use strict'; |
| 56 | + |
| 57 | +var LocalServiceRegistry = require('dw/svc/LocalServiceRegistry'); |
| 58 | + |
| 59 | +var myService = LocalServiceRegistry.createService('my.service.id', { |
| 60 | + /** |
| 61 | + * Configure the request before it is sent |
| 62 | + * @param {dw.svc.HTTPService} svc - The service instance |
| 63 | + * @param {Object} params - Parameters passed to service.call() |
| 64 | + * @returns {string} Request body |
| 65 | + */ |
| 66 | + createRequest: function (svc, params) { |
| 67 | + svc.setRequestMethod('POST'); |
| 68 | + svc.addHeader('Content-Type', 'application/json'); |
| 69 | + return JSON.stringify(params); |
| 70 | + }, |
| 71 | + |
| 72 | + /** |
| 73 | + * Parse the response after a successful call |
| 74 | + * @param {dw.svc.HTTPService} svc - The service instance |
| 75 | + * @param {dw.net.HTTPClient} client - The HTTP client with response |
| 76 | + * @returns {Object} Parsed response |
| 77 | + */ |
| 78 | + parseResponse: function (svc, client) { |
| 79 | + return JSON.parse(client.text); |
| 80 | + }, |
| 81 | + |
| 82 | + /** |
| 83 | + * Filter sensitive data from logs (required for production) |
| 84 | + * @param {string} msg - The message to filter |
| 85 | + * @returns {string} Filtered message |
| 86 | + */ |
| 87 | + filterLogMessage: function (msg) { |
| 88 | + return msg.replace(/("api_key"\s*:\s*")[^"]+"/g, '$1***"'); |
| 89 | + } |
| 90 | +}); |
| 91 | + |
| 92 | +// Call the service |
| 93 | +var result = myService.call({ key: 'value' }); |
| 94 | + |
| 95 | +if (result.ok) { |
| 96 | + var data = result.object; |
| 97 | +} else { |
| 98 | + var error = result.errorMessage; |
| 99 | +} |
| 100 | +``` |
| 101 | + |
| 102 | +## Service Callbacks |
| 103 | + |
| 104 | +| Callback | Required | Description | |
| 105 | +|----------|----------|-------------| |
| 106 | +| `createRequest` | Yes* | Configure request, return body | |
| 107 | +| `parseResponse` | Yes* | Parse response, return result object | |
| 108 | +| `execute` | No | Custom execution logic (replaces default) | |
| 109 | +| `initServiceClient` | No | Create/configure underlying client | |
| 110 | +| `mockCall` | No | Return mock response (execute phase only) | |
| 111 | +| `mockFull` | No | Return mock response (entire call) | |
| 112 | +| `filterLogMessage` | Recommended | Filter sensitive data from logs | |
| 113 | +| `getRequestLogMessage` | No | Custom request log message | |
| 114 | +| `getResponseLogMessage` | No | Custom response log message | |
| 115 | + |
| 116 | +*Required unless `execute` is implemented |
| 117 | + |
| 118 | +## Result Object |
| 119 | + |
| 120 | +The `call()` method returns a `dw.svc.Result`: |
| 121 | + |
| 122 | +| Property | Type | Description | |
| 123 | +|----------|------|-------------| |
| 124 | +| `ok` | Boolean | True if successful | |
| 125 | +| `status` | String | "OK", "ERROR", or "SERVICE_UNAVAILABLE" | |
| 126 | +| `object` | Object | Response from `parseResponse` | |
| 127 | +| `error` | Number | Error code (e.g., HTTP status) | |
| 128 | +| `errorMessage` | String | Error description | |
| 129 | +| `unavailableReason` | String | Why service is unavailable | |
| 130 | +| `mockResult` | Boolean | True if from mock callback | |
| 131 | + |
| 132 | +### Unavailable Reasons |
| 133 | + |
| 134 | +| Reason | Description | |
| 135 | +|--------|-------------| |
| 136 | +| `TIMEOUT` | Call timed out | |
| 137 | +| `RATE_LIMITED` | Rate limit exceeded | |
| 138 | +| `CIRCUIT_BROKEN` | Circuit breaker open | |
| 139 | +| `DISABLED` | Service disabled | |
| 140 | +| `CONFIG_PROBLEM` | Configuration error | |
| 141 | + |
| 142 | +## Error Handling |
| 143 | + |
| 144 | +```javascript |
| 145 | +var result = myService.call(params); |
| 146 | + |
| 147 | +if (result.ok) { |
| 148 | + return result.object; |
| 149 | +} |
| 150 | + |
| 151 | +// Handle different error types |
| 152 | +switch (result.status) { |
| 153 | + case 'SERVICE_UNAVAILABLE': |
| 154 | + switch (result.unavailableReason) { |
| 155 | + case 'RATE_LIMITED': |
| 156 | + // Retry later |
| 157 | + break; |
| 158 | + case 'CIRCUIT_BROKEN': |
| 159 | + // Service is down, use fallback |
| 160 | + break; |
| 161 | + case 'TIMEOUT': |
| 162 | + // Request timed out |
| 163 | + break; |
| 164 | + } |
| 165 | + break; |
| 166 | + case 'ERROR': |
| 167 | + // Check HTTP status code |
| 168 | + if (result.error === 401) { |
| 169 | + // Authentication error |
| 170 | + } else if (result.error === 404) { |
| 171 | + // Resource not found |
| 172 | + } |
| 173 | + break; |
| 174 | +} |
| 175 | + |
| 176 | +throw new Error('Service error: ' + result.errorMessage); |
| 177 | +``` |
| 178 | + |
| 179 | +## Log Filtering |
| 180 | + |
| 181 | +Production environments require log filtering to prevent sensitive data exposure: |
| 182 | + |
| 183 | +```javascript |
| 184 | +var myService = LocalServiceRegistry.createService('my.service', { |
| 185 | + createRequest: function (svc, params) { |
| 186 | + // ... configure request |
| 187 | + }, |
| 188 | + |
| 189 | + parseResponse: function (svc, client) { |
| 190 | + return JSON.parse(client.text); |
| 191 | + }, |
| 192 | + |
| 193 | + /** |
| 194 | + * Filter sensitive data from all log messages |
| 195 | + */ |
| 196 | + filterLogMessage: function (msg) { |
| 197 | + // Filter API keys |
| 198 | + msg = msg.replace(/api_key=[^&]+/g, 'api_key=***'); |
| 199 | + // Filter authorization headers |
| 200 | + msg = msg.replace(/Authorization:\s*[^\r\n]+/gi, 'Authorization: ***'); |
| 201 | + // Filter passwords in JSON |
| 202 | + msg = msg.replace(/("password"\s*:\s*")[^"]+"/g, '$1***"'); |
| 203 | + return msg; |
| 204 | + }, |
| 205 | + |
| 206 | + /** |
| 207 | + * Custom request log message (optional) |
| 208 | + */ |
| 209 | + getRequestLogMessage: function (request) { |
| 210 | + // Return custom message or null for default |
| 211 | + return 'Request: ' + request.substring(0, 100) + '...'; |
| 212 | + }, |
| 213 | + |
| 214 | + /** |
| 215 | + * Custom response log message (optional) |
| 216 | + */ |
| 217 | + getResponseLogMessage: function (response) { |
| 218 | + // Return custom message or null for default |
| 219 | + return 'Response received'; |
| 220 | + } |
| 221 | +}); |
| 222 | +``` |
| 223 | + |
| 224 | +## Mocking Services |
| 225 | + |
| 226 | +Use mock callbacks for testing without external calls: |
| 227 | + |
| 228 | +```javascript |
| 229 | +var myService = LocalServiceRegistry.createService('my.service', { |
| 230 | + createRequest: function (svc, params) { |
| 231 | + svc.setRequestMethod('GET'); |
| 232 | + svc.addParam('id', params.id); |
| 233 | + return null; |
| 234 | + }, |
| 235 | + |
| 236 | + parseResponse: function (svc, client) { |
| 237 | + return JSON.parse(client.text); |
| 238 | + }, |
| 239 | + |
| 240 | + /** |
| 241 | + * Mock the execute phase only (createRequest and parseResponse still run) |
| 242 | + */ |
| 243 | + mockCall: function (svc, request) { |
| 244 | + return { |
| 245 | + statusCode: 200, |
| 246 | + text: JSON.stringify({ id: 1, name: 'Mock Data' }) |
| 247 | + }; |
| 248 | + }, |
| 249 | + |
| 250 | + /** |
| 251 | + * Or mock the entire call (replaces all phases) |
| 252 | + */ |
| 253 | + mockFull: function (svc, params) { |
| 254 | + return { id: params.id, name: 'Full Mock Data' }; |
| 255 | + } |
| 256 | +}); |
| 257 | + |
| 258 | +// Force mock mode |
| 259 | +myService.setMock(); |
| 260 | +var result = myService.call({ id: 123 }); |
| 261 | +``` |
| 262 | + |
| 263 | +## Service Configuration in Business Manager |
| 264 | + |
| 265 | +### Creating a Service |
| 266 | + |
| 267 | +1. Go to **Administration > Operations > Services** |
| 268 | +2. Click **New** under Service Configurations |
| 269 | +3. Fill in: |
| 270 | + - **Service ID**: Unique identifier (e.g., `my.api.service`) |
| 271 | + - **Service Type**: HTTP, FTP, SOAP, etc. |
| 272 | + - **Enabled**: Check to enable |
| 273 | + - **Profile**: Select or create a profile |
| 274 | + - **Credential**: Select or create credentials |
| 275 | + - **Communication Log**: Enable for debugging |
| 276 | + |
| 277 | +### Service Profile Settings |
| 278 | + |
| 279 | +| Setting | Description | |
| 280 | +|---------|-------------| |
| 281 | +| **Timeout** | Maximum wait time in milliseconds | |
| 282 | +| **Rate Limit** | Maximum calls per time unit | |
| 283 | +| **Circuit Breaker Enabled** | Enable automatic failure handling | |
| 284 | +| **Max Circuit Breaker Calls** | Calls before circuit opens | |
| 285 | +| **Circuit Breaker Interval** | Time window for tracking failures | |
| 286 | + |
| 287 | +### Service Credential Settings |
| 288 | + |
| 289 | +| Setting | Description | |
| 290 | +|---------|-------------| |
| 291 | +| **ID** | Credential identifier | |
| 292 | +| **URL** | Base URL for the service | |
| 293 | +| **User** | Username for authentication | |
| 294 | +| **Password** | Password for authentication | |
| 295 | + |
| 296 | +## Detailed References |
| 297 | + |
| 298 | +- [HTTP Services](references/HTTP-SERVICES.md) - REST API integrations |
| 299 | +- [FTP/SFTP Services](references/FTP-SERVICES.md) - File transfer operations |
| 300 | +- [SOAP Services](references/SOAP-SERVICES.md) - SOAP web service integrations |
| 301 | +- [Services XML](references/SERVICES-XML.md) - Import/export service configurations |
| 302 | + |
| 303 | +## Script API Classes |
| 304 | + |
| 305 | +| Class | Description | |
| 306 | +|-------|-------------| |
| 307 | +| `dw.svc.LocalServiceRegistry` | Create service instances | |
| 308 | +| `dw.svc.Service` | Base service class | |
| 309 | +| `dw.svc.HTTPService` | HTTP service methods | |
| 310 | +| `dw.svc.FTPService` | FTP/SFTP service methods | |
| 311 | +| `dw.svc.SOAPService` | SOAP service methods | |
| 312 | +| `dw.svc.Result` | Service call result | |
| 313 | +| `dw.svc.ServiceConfig` | Service configuration | |
| 314 | +| `dw.svc.ServiceProfile` | Rate limit/circuit breaker config | |
| 315 | +| `dw.svc.ServiceCredential` | Authentication credentials | |
| 316 | +| `dw.net.HTTPClient` | Underlying HTTP client | |
| 317 | +| `dw.net.FTPClient` | Underlying FTP client | |
| 318 | +| `dw.net.SFTPClient` | Underlying SFTP client | |
0 commit comments