Skip to content

Commit 0bb9a29

Browse files
committed
Add b2c-webservices skill for web service integrations
Comprehensive skill covering: - Service Framework overview and components - LocalServiceRegistry.createService() pattern - Service callbacks (createRequest, parseResponse, execute, etc.) - Result object handling and error states - Log filtering for sensitive data Reference documentation includes: - HTTP-SERVICES.md: REST API patterns, authentication (Basic, OAuth, API keys), multipart uploads, file downloads, response caching, mTLS - FTP-SERVICES.md: SFTP operations (list, get, put, delete), multi-operation patterns, file processing workflows - SOAP-SERVICES.md: WSDL stubs, WS-Security, WSUtil, custom headers, complex types, MTOM attachments - SERVICES-XML.md: XML import/export format for service configurations, credentials, profiles, and services
1 parent 0e2c956 commit 0bb9a29

5 files changed

Lines changed: 2327 additions & 0 deletions

File tree

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
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

Comments
 (0)