Advanced 35 min read

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:

  1. A Named Credential (Exchange_Rate_API, Lesson 2) storing the endpoint and authentication.
  2. A thin Controller and a Service class (Module 16's layering) making the callout and mapping the response.
  3. Robust status code and CalloutException handling (Lesson 4), surfaced as a clear AuraHandledException.
  4. 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.

JAVASCRIPT

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.

APEX

Project: LWC Calling a Secure External REST Service Quiz

1. What handles the actual external HTTP callout in this project?

2. Why is convert() called imperatively rather than via @wire?

3. What does isConverting control in the component?

4. What happens if the external exchange rate service is unreachable?

5. Where does the actual endpoint URL and authentication for the exchange rate API live?

Log in to submit the quiz and save your score.

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.