Agent skill
b2c-webservices
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.
Install this agent skill to your Project
npx add-skill https://github.com/SalesforceCommerceCloud/b2c-developer-tooling/tree/main/skills/b2c/skills/b2c-webservices
SKILL.md
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:
- Service Configuration - General settings (enabled, logging, callbacks)
- Service Profile - Rate limiting and circuit breaker settings
- 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
'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
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:
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:
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
- Go to Administration > Operations > Services
- Click New under Service Configurations
- 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 ID: Unique identifier (e.g.,
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 - REST API integrations
- FTP/SFTP Services - File transfer operations
- SOAP Services - SOAP web service integrations
- Services XML - 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 |
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
api-client-development
Creating typed API clients with OpenAPI specs, authentication, and OAuth scopes for SCAPI and similar APIs. Use when adding a new SCAPI client, generating types from an OpenAPI spec, setting up OAuth middleware, or integrating a new Commerce API endpoint.
testing
Writing tests for the B2C CLI project using Mocha, Chai, and MSW. Use when writing unit or integration tests, mocking HTTP requests with MSW, testing CLI commands with oclif, isolating config in tests, setting up test coverage, using sinon stubs, c8 coverage, capturing or silencing stdout, or creating MSW handlers.
documentation
Updating user guides, CLI reference, and API documentation for the B2C CLI project. Use when adding or changing CLI command docs, writing JSDoc for TypeDoc generation, updating Vitepress sidebar config, or creating new guide pages.
cli-command-development
Creating new CLI commands and topics for the B2C CLI using oclif. Use when adding a new command, creating a topic, adding flags or arguments, implementing table output, or extending BaseCommand/OAuthCommand/InstanceCommand.
sdk-module-development
Adding new modules and exports to the @salesforce/b2c-tooling-sdk package. Use when creating a new SDK module, adding barrel file exports, configuring package.json exports, or building client factory functions.
b2c-code
Deploy and manage code versions/cartridges on B2C Commerce instances/sandboxes with the b2c cli. Always reference when using the CLI to upload cartridges, deploy code, activate code versions, manage code versions, or watch for file changes during development.
Didn't find tool you were looking for?