Project: External API Integration Component
By the end of this lesson, you'll be able to:
- Apply Module 17's full integration architecture to a new realistic scenario
- Reuse the Named Credential/Service/error-handling pattern for a different external API
- Provide a robust, loading-state-aware client experience for an external lookup
Prerequisites: "Project: Document Upload Component"
What We're Building
A shipmentTracker component looking up a shipment's status from an external carrier API, reusing Module 17's exact architecture: Named Credential → Service → Controller → component, with full error/timeout handling.
The Apex Layer
public inherited sharing class ShipmentTrackingService {
public static ShipmentStatus track(String trackingNumber) {
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:Carrier_API/track/' + EncodingUtil.urlEncode(trackingNumber, 'UTF-8'));
request.setMethod('GET');
HttpResponse response;
try {
response = new Http().send(request);
} catch (CalloutException e) {
throw new AuraHandledException('Could not reach the carrier service. Please try again.');
}
if (response.getStatusCode() != 200) {
throw new AuraHandledException('Tracking number not found.');
}
CarrierResponse raw = (CarrierResponse) JSON.deserialize(response.getBody(), CarrierResponse.class);
return new ShipmentStatus(raw.status, raw.estimatedDelivery);
}
}
public with sharing class ShipmentTrackingController {
@AuraEnabled
public static ShipmentStatus track(String trackingNumber) {
return ShipmentTrackingService.track(trackingNumber);
}
}
Every piece — the Named Credential reference, CalloutException/status-code handling, the wrapper class — is the identical pattern from Module 17's currency converter, applied to a completely different external system.
The Component
async handleTrack() {
this.isTracking = true;
try {
this.shipmentStatus = await track({ trackingNumber: this.trackingNumber });
} catch (error) {
this.dispatchEvent(new ShowToastEvent({
title: 'Tracking Failed',
message: error.body?.message ?? 'An unexpected error occurred.',
variant: 'error',
}));
} finally {
this.isTracking = false;
}
}
Called imperatively — triggered by a specific "Track" button click, not something that should load automatically — exactly Module 7's decision table applied once more.
Exercise
Explain, as a comment, what would need to change to reuse this same architecture for a completely different external API (e.g. a weather service).
Show hint
Think about what genuinely stays the same versus what's specific to this one integration.
Exercise
Challenge: why is track() called imperatively rather than via @wire?
Show hint
Recall Module 7's decision table.
Project: External API Integration Component Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
A shipment-tracking lookup applying Module 17's entire integration pattern to a new scenario — proof the architecture generalizes to any external REST API, not just the one worked example.