Project: LWC Calling a Secure External REST Service
By the end of this lesson, you'll be able to:
- Combine Named Credentials, a callout service, and JSON mapping into one integration
- Apply robust status/exception handling for the external call
- Build a component with a proper loading state and toast feedback for the integration
Prerequisites: "Loading States, Errors, and Timeouts in Integrations"
What We're Building
A currencyConverter component that calls an external exchange-rate API to convert an amount between currencies:
- A Named Credential (
Exchange_Rate_API, Lesson 2) storing the endpoint and authentication. - A thin Controller and a Service class (Module 16's layering) making the callout and mapping the response.
- Robust status code and CalloutException handling (Lesson 4), surfaced as a clear
AuraHandledException. - A component with a loading state and toast feedback (Module 8) for the conversion action.
The Apex Layer
// Service — the actual integration logic
public inherited sharing class ExchangeRateService {
public static Decimal convert(String fromCurrency, String toCurrency, Decimal amount) {
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:Exchange_Rate_API/convert?from=' + fromCurrency + '&to=' + toCurrency);
request.setMethod('GET');
HttpResponse response;
try {
response = new Http().send(request);
} catch (CalloutException e) {
throw new AuraHandledException('Could not reach the exchange rate service. Please try again.');
}
if (response.getStatusCode() != 200) {
throw new AuraHandledException('Exchange rate service returned an unexpected response.');
}
ExchangeRateResponse rate = (ExchangeRateResponse) JSON.deserialize(response.getBody(), ExchangeRateResponse.class);
return amount * rate.rate;
}
}
public class ExchangeRateResponse {
public Decimal rate;
}
// Controller — thin, LWC-facing
public with sharing class CurrencyConverterController {
@AuraEnabled
public static Decimal convert(String fromCurrency, String toCurrency, Decimal amount) {
return ExchangeRateService.convert(fromCurrency, toCurrency, amount);
}
}
The Component
import { LightningElement } from 'lwc';
import convert from '@salesforce/apex/CurrencyConverterController.convert';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
export default class CurrencyConverter extends LightningElement {
fromCurrency = 'USD';
toCurrency = 'ZAR';
amount = 0;
convertedAmount;
isConverting = false;
async handleConvert() {
this.isConverting = true;
try {
this.convertedAmount = await convert({
fromCurrency: this.fromCurrency,
toCurrency: this.toCurrency,
amount: this.amount,
});
} catch (error) {
this.dispatchEvent(new ShowToastEvent({
title: 'Conversion Failed',
message: error.body?.message ?? 'An unexpected error occurred.',
variant: 'error',
}));
} finally {
this.isConverting = false;
}
}
}
This method is called imperatively (Module 7's decision table), not via @wire — it's triggered by a specific user action (clicking "Convert"), not something that should load automatically on render. Every module referenced here — DTOs (Module 7), Controller/Service layering (Module 16), loading states and toasts (Module 8) — comes together in one realistic feature.
Exercise
Explain, as a comment, why convert() is called imperatively from the component rather than via @wire.
Show hint
Recall Module 7's decision table for choosing between the two.
Exercise
Challenge: explain, as a comment, why the Named Credential name is embedded in the endpoint string (callout:Exchange_Rate_API/...) rather than the raw API URL.
Show hint
Recall Lesson 2's reasoning for Named Credentials.
Project: LWC Calling a Secure External REST Service 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 hands-on capstone assembling every piece of this module into one realistic, secure integration — from Named Credential to a polished, loading-state-aware component.