mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-08-03 13:44:09 +08:00
5.5 KiB
5.5 KiB
External Service Operations Guide
Overview
External Services in Salesforce auto-generate Apex classes from OpenAPI specifications, providing type-safe API integrations without manual HTTP code.
Generated Class Structure
When you register an External Service named MyAPI, Salesforce generates:
ExternalService.MyAPI - Main service class
ExternalService.MyAPI_operationName_Request - Request wrapper for each operation
ExternalService.MyAPI_operationName_Response - Response wrapper for each operation
ExternalService.MyAPI_SchemaName - DTO for each schema in OpenAPI
Basic Usage
1. Instantiate the Service
ExternalService.MyAPI api = new ExternalService.MyAPI();
2. Call GET Operation
// Simple GET with path parameter
ExternalService.MyAPI_getCustomer_Response response = api.getCustomer('cust_123');
// Access response data
String customerId = response.id;
String customerName = response.name;
3. Call POST Operation
// Create request object
ExternalService.MyAPI_createCustomer_Request request =
new ExternalService.MyAPI_createCustomer_Request();
request.name = 'Acme Corp';
request.email = 'contact@acme.com';
// Make the call
ExternalService.MyAPI_createCustomer_Response response = api.createCustomer(request);
// Access created resource
String newCustomerId = response.id;
4. Call PUT/PATCH Operations
// Update request
ExternalService.MyAPI_updateCustomer_Request request =
new ExternalService.MyAPI_updateCustomer_Request();
request.customerId = 'cust_123'; // Path parameter
request.name = 'Acme Corporation'; // Body field
ExternalService.MyAPI_updateCustomer_Response response = api.updateCustomer(request);
5. Call DELETE Operation
// DELETE usually returns void or simple confirmation
api.deleteCustomer('cust_123');
Error Handling
try {
ExternalService.MyAPI api = new ExternalService.MyAPI();
ExternalService.MyAPI_getCustomer_Response response = api.getCustomer('invalid_id');
} catch (ExternalService.ExternalServiceException e) {
// API returned error status code
System.debug('API Error: ' + e.getMessage());
System.debug('Status Code: ' + e.getStatusCode());
System.debug('Response Body: ' + e.getBody());
} catch (CalloutException e) {
// Network/connection error
System.debug('Callout failed: ' + e.getMessage());
}
Async Usage (Queueable)
External Service calls are still callouts, so use Queueable for trigger contexts:
public class CustomerSyncQueueable implements Queueable, Database.AllowsCallouts {
private List<Account> accounts;
public CustomerSyncQueueable(List<Account> accounts) {
this.accounts = accounts;
}
public void execute(QueueableContext context) {
ExternalService.MyAPI api = new ExternalService.MyAPI();
for (Account acc : accounts) {
try {
ExternalService.MyAPI_createCustomer_Request req =
new ExternalService.MyAPI_createCustomer_Request();
req.name = acc.Name;
req.email = acc.Email__c;
ExternalService.MyAPI_createCustomer_Response resp =
api.createCustomer(req);
// Store external ID on Account
acc.External_Customer_Id__c = resp.id;
} catch (Exception e) {
System.debug('Sync failed for ' + acc.Name + ': ' + e.getMessage());
}
}
update accounts;
}
}
OpenAPI Schema Tips
Required Properties
{
"components": {
"schemas": {
"Customer": {
"type": "object",
"required": ["name", "email"],
"properties": {
"name": { "type": "string" },
"email": { "type": "string", "format": "email" }
}
}
}
}
}
Nested Objects
{
"Customer": {
"type": "object",
"properties": {
"address": {
"$ref": "#/components/schemas/Address"
}
}
},
"Address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
}
}
}
Arrays
{
"CustomerList": {
"type": "object",
"properties": {
"customers": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Customer"
}
}
}
}
}
Limitations
| Limitation | Workaround |
|---|---|
| 100 callouts per transaction | Use async (Queueable) with chaining |
| 120s max timeout | Use shorter timeout, implement retry |
| 6MB response size | Paginate responses, compress data |
| Some OpenAPI features not supported | Simplify schema, avoid oneOf/anyOf |
Refreshing External Service
When the API schema changes:
- Download updated OpenAPI spec
- Go to Setup → External Services
- Edit the service
- Upload new schema
- Review generated operations
- Save and validate
Or via metadata deployment:
- Update the
<schema>content in the.externalServiceRegistration-meta.xml - Deploy with
sf project deploy start
Best Practices
- Version Your APIs: Include version in Named Credential endpoint
- Handle All Errors: Catch both
ExternalServiceExceptionandCalloutException - Log Requests/Responses: For debugging production issues
- Use Async: Always use Queueable when called from DML contexts
- Test Thoroughly: Mock External Service calls in test classes