A REST callout from Apex is just an HTTP request to an external service. Apex gives you three classes — Http, HttpRequest, HttpResponse — and you assemble the call by hand.
The shape every REST callout takes
public class WeatherService {
public static Decimal getTempC(String city) {
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:Weather_API/v1/current?city=' + EncodingUtil.urlEncode(city, 'UTF-8'));
req.setMethod('GET');
req.setHeader('Accept', 'application/json');
req.setTimeout(20000); // ms, max 120000
HttpResponse res = new Http().send(req);
if (res.getStatusCode() != 200) {
throw new CalloutException('Weather API returned ' + res.getStatusCode());
}
Map<String, Object> body = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
return (Decimal) body.get('temp_c');
}
}
What the platform requires
- Endpoint must be whitelisted. Either reference a Named Credential (
callout:Weather_API/...) — the recommended path — or add the raw host to Setup > Remote Site Settings. Without one of those, the callout throwsSystem.CalloutException: Unauthorized endpoint. - No callouts after DML in the same transaction. Make the callout first, then write the result. If you can’t reorder, push the callout to
@future(callout=true)or Queueable. - No callouts from triggers synchronously. Trigger fires, you enqueue async work, the async job makes the callout.
Governor limits
| Limit | Value |
|---|---|
| Callouts per transaction | 100 |
| Total callout time per transaction | 120 seconds |
| Single callout timeout | 120 seconds (default 10) |
| Request/response size | 6 MB sync, 12 MB async |
Authentication: use Named Credentials
Named Credentials store the endpoint and the auth handshake — OAuth 2.0, JWT, basic, AWS Signature v4. Apex code references callout:My_Credential and never sees the secret. Without them you’d be hardcoding tokens, which fails security review.
Common interview follow-ups
- POST a JSON body? —
req.setBody(JSON.serialize(payload));andreq.setHeader('Content-Type', 'application/json');. - How do you test it? — Implement
HttpCalloutMock, register withTest.setMock(). Real HTTP calls aren’t allowed in tests. - What if the response is huge? — Use
req.setCompressed(true)for gzip, and process in async if needed for the 12 MB limit.
Verified against: Apex Developer Guide — Invoking Callouts Using Apex. Last reviewed 2026-05-17 for Spring ‘26 release.