Calling external APIs from AEM
Purpose: The standard shape for outbound HTTP: a configured OSGi service using a managed HttpClient.
Who this page is for
| Audience | Why it matters to you |
|---|
| Backend engineers | The template for every outbound call |
The standard shape
One OSGi service per upstream system, wrapping a shared, pooled Apache HttpClient, with endpoint/timeout config per run mode:
@Component(service = RatingClient.class)
@Designate(ocd = RatingClient.Config.class)
public class RatingClient {
@ObjectClassDefinition interface Config {
@AttributeDefinition String endpoint();
@AttributeDefinition int timeoutMs() default 800;
}
private CloseableHttpClient http;
private Config cfg;
@Activate void activate(Config cfg) {
this.cfg = cfg;
this.http = HttpClients.custom()
.setConnectionManager(pooled(20))
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectTimeout(cfg.timeoutMs())
.setSocketTimeout(cfg.timeoutMs()).build())
.build();
}
@Deactivate void deactivate() throws IOException { http.close(); }
public Optional<Quote> quote(String planId) { /* GET, map, catch, Optional.empty() on failure */ }
}
Non-negotiables
| Rule | Why |
|---|
| Connect + socket timeouts always set | Default is effectively infinite; one hung upstream exhausts render threads |
| Pooled connection manager, sized deliberately | Per-request clients leak sockets |
| Return Optional/fallback, never throw into HTL | Pages must render through outages |
| Endpoint per run mode (ui.config) | dev hits mocks, prod hits prod |
| Auth via secrets mechanism | Not in code, not in repo config (secrets) |
| Log with correlation ID, no payload PII | Debuggability without leakage |
Where calls may run
| Context | Verdict |
|---|
| Scheduled job / Sling job | ✔ ideal — async, retryable |
| Servlet handling an explicit AJAX request | ✔ with timeouts — user asked for live data |
| Sling Model during page render | ⚠ only with cache + tight timeout + fallback; prefer avoiding |
| Workflow process step | ✔ (async by nature) |
| Event listener thread | ✗ enqueue a job instead |