The Dependency That Can Break Your Application
Modern web applications are built on a foundation of third-party API integrations: payment processors, authentication services, mapping APIs, communication platforms, analytics services, AI APIs, and dozens of other specialised services that application developers integrate rather than build themselves. This integration approach accelerates development, provides access to capabilities that would take months to build, and leverages the expertise of specialised providers. It also introduces a category of failure that the application developer doesn’t fully control: the third-party service that goes down, rate-limits aggressively, changes its API without notice, or terminates a free tier that the application depended on.
Building applications that integrate third-party APIs in ways that handle these failure modes gracefully — rather than propagating third-party failures into user-visible application failures — is the resilience engineering practice that separates robust applications from fragile ones.
Rate Limiting: Understanding and Handling Limits
Most third-party APIs implement rate limiting — maximum request frequency constraints that prevent individual consumers from overloading the shared infrastructure. Rate limits are expressed in various ways (requests per second, requests per minute, requests per day, tokens per minute for LLM APIs) and enforced through HTTP 429 responses when limits are exceeded. Exceeding a rate limit produces errors in the application unless the application handles the 429 response appropriately.
The rate limiting handling strategies: exponential backoff with jitter (when a rate limit response is received, wait a progressively longer interval before retrying, with randomisation to prevent thundering herd when many instances retry simultaneously), request queuing (buffer requests and dispatch them at a rate below the limit rather than sending them as fast as they arrive), and caching (storing API responses and serving cached results for identical requests within a TTL, reducing the total API call volume). Which strategy is appropriate depends on whether the rate-limited requests are latency-sensitive (user is waiting for the response) or background (processing can be deferred).
Circuit Breakers: Stopping the Cascade
A circuit breaker is a pattern that stops making requests to a failing service rather than allowing failures to cascade into a flood of error requests. When a service begins returning errors above a threshold rate, the circuit breaker ‘opens’ — subsequent calls to the service fail immediately without attempting the network request — for a defined period, after which it allows test requests through to check whether the service has recovered. This prevents the application from spending resources on requests that are going to fail anyway and protects the struggling service from additional load during an incident.
Circuit breaker libraries exist for most major programming languages: Resilience4j for Java, Hystrix (though in maintenance mode) for JVM languages, Polly for .NET, and custom implementations in Python, Node.js, and Go are straightforward given the pattern’s simplicity. For applications that make high-volume calls to external services, the circuit breaker pattern is the most important resilience primitive to implement alongside retry logic.
Fallback Strategies: Degraded Service Rather Than No Service
When a third-party API is unavailable, the application can respond in three ways: fail completely (user sees an error), wait (user waits indefinitely for a response that won’t come), or degrade gracefully (provide a reduced experience that doesn’t depend on the unavailable service). Graceful degradation — the third option — is the engineering choice that produces the best user experience during third-party incidents.
Fallback implementations depend on the service’s function: a payment processor integration that’s unavailable can show a maintenance message while queue the order for processing when service resumes; a mapping API that’s unavailable can show a text address rather than a map; an AI API that’s unavailable can show a message that AI features are temporarily unavailable rather than preventing the user from using other application features. The specific fallback depends on whether the API call is blocking (required for the page to function) or enriching (adds functionality without being required for basic function).
Monitoring and Alerting for Third-Party Dependencies
Application monitoring that doesn’t include third-party API response times, error rates, and availability provides an incomplete picture of application health. A third-party API that begins responding slowly degrades application performance in ways that application-level monitoring of database queries and server response times doesn’t surface. Distributed tracing that includes external API calls (Datadog APM, New Relic, Honeycomb, OpenTelemetry) provides visibility into the external API contribution to total request latency.
Subscribing to status pages of critical third-party APIs (most major API providers maintain status pages accessible at status.provider.com or via StatusPage) provides advance notice of known incidents. Automated alerting (PagerDuty, Opsgenie alerts configured to trigger when third-party error rates exceed thresholds) ensures that third-party API failures are detected at the application level rather than discovered through user complaints. The combination of proactive status page monitoring and reactive application-level alerting provides the coverage needed to respond to third-party incidents before they cause extended user-visible failures.
