|
Voiced by Amazon Polly |
Overview
Modern applications often need information that they don’t generate themselves. Weather data is a good example. A travel application, food-delivery platform, agriculture system, or location-based service may need the current temperature, humidity, wind speed, or weather conditions for a particular city.
Instead of building and maintaining a weather-data system from scratch, we can consume data from an existing third-party weather API and expose it through our own API.
At first, this sounds simple: receive a city name, call the weather API, and return the response. But a production-ready implementation requires much more thought. We need to consider API design, validation, error handling, security, timeouts, retries, caching, and dependency failures.
Let’s understand how to design such a system.
Pioneers in Cloud Consulting & Migration Services
- Reduced infrastructural costs
- Accelerated application deployment
The Basic Architecture
Suppose our application exposes the following endpoint:
GET /weather?city=Bangalore
The overall flow would look like this:
Client → Our Weather API → Third-Party Weather API → Our Weather API → Client
The client should ideally communicate only with our API. It should not directly call the third-party weather provider.
For example:
- The client sends a request for Bangalore.
- Our API validates the city name.
- Our backend calls the third-party weather API.
- The third-party API returns weather information.
- Our backend transforms the response into our application’s format.
- Our API sends the response back to the client.
This approach gives us control over how external data is consumed and exposed.
Why Not Call the Third-Party API Directly?
You might wonder: if the weather provider already has an API, why create another API?
There are several good reasons.
Security
The third-party API may require an API key. If the frontend calls the provider directly, that key could be exposed.
By keeping the API key on the backend, we can protect it using environment variables or a secrets manager.
Abstraction
Third-party APIs can change. Their response format, endpoint, authentication mechanism, or pricing may change in the future.
If our application communicates through our own API, only our backend integration needs to change. The clients can continue using the same contract.
Data Transformation
The third-party API might return a large response containing dozens of fields.
Our application may only need:
|
1 2 3 4 5 6 |
{ "city": "Bangalore", "temperature": 28, "humidity": 72, "condition": "Cloudy" } |
Our API can hide unnecessary details and expose only what the application requires.
Designing the API Contract
Before writing code, we should define our API contract.
For example:
GET /api/v1/weather?city=Bangalore
A successful response could be:
|
1 2 3 4 5 6 |
{ "city": "Bangalore", "temperature": 28, "humidity": 72, "condition": "Cloudy" } |
The important point here is that our API contract should be independent of the third-party provider’s response.
This creates a clean separation:
Our API contract → Integration layer → Third-party API
If the provider changes its response from temp to temperature, our clients don’t need to know about that change.
Handling the Third-Party Integration
A clean backend design should separate responsibilities.
For example:
|
1 2 3 4 5 6 7 |
Controller / Route ↓ Weather Service ↓ Weather Provider Client ↓ Third-Party API |
The route handles the incoming HTTP request.
The service contains business logic.
The provider client is responsible for communicating with the external weather API.
This separation makes the code easier to test and maintain.
For example, in a Python application using FastAPI, we could have:
routes/weather.py
services/weather_service.py
clients/weather_client.py
models/weather.py
The weather_client should know how to communicate with the external provider, while the weather_service should decide what information our application needs.
Error Handling Is Extremely Important
A common mistake is assuming that the third-party API will always work.
It won’t.
The provider might be unavailable, return a timeout, reject our API key, or report that the requested city doesn’t exist.
Our API should handle these situations gracefully.
For example:
|
1 2 3 4 5 6 7 8 9 10 |
Invalid city HTTP 404 { "error": "City not found" } Third-party service unavailable HTTP 503 { "error": "Weather service temporarily unavailable" } |
Request timeout
Instead of keeping our client waiting indefinitely, we should configure a reasonable timeout.
This is important because an external API is a dependency outside our control.
Timeouts and Retries
Imagine our API waits 60 seconds for the weather provider.
Now imagine 100 users making requests simultaneously.
Our application could quickly become overloaded because all those requests are waiting for the external service.
Therefore, we should configure short and sensible connection and read timeouts.
Retries can also help with temporary failures. However, retries should not be implemented blindly.
A common approach is to retry only transient failures and use exponential backoff.
For example:
Attempt 1 → immediately
Attempt 2 → after 1 second
Attempt 3 → after 2 seconds
We should also limit the number of retries.
Otherwise, our application could generate even more traffic when the external service is already struggling.
Caching Can Improve Performance
Weather data usually doesn’t need to be fetched every second.
If 1,000 users request Bangalore’s weather within a short period, repeatedly calling the third-party API is unnecessary.
We can cache the response.
For example:
Request → Check Cache
↓
Data available?
/ \
Yes No
↓ ↓
Return Call API
↓
Store Cache
↓
Return
Redis is a common choice for this type of caching.
We could cache Bangalore’s weather for a few minutes, depending on the application’s requirements.
Caching reduces latency, decreases third-party API usage, and can also protect us from exceeding provider rate limits.
Rate Limiting
Our API should also protect itself from excessive client requests.
For example, we might limit a client to a certain number of requests per minute.
Rate limiting is particularly useful when the third-party provider also imposes usage limits.
Without rate limiting, a sudden traffic spike could cause our application to make thousands of unnecessary external requests.
Monitoring and Logging
A production API should not simply work; we should also know when it stops working.
Useful metrics include:
- API response time
- Third-party API response time
- Error rate
- Timeout count
- Cache hit ratio
- Number of third-party requests
- Rate-limit errors
Logs should contain enough information to troubleshoot failures without exposing sensitive information such as API keys.
For example:
Request: city=Bangalore
Provider response: 200
Response time: 180ms
Cache: MISS
This makes debugging significantly easier.
The Final Design
A simple but production-friendly architecture could look like this:
┌─────────────────┐
│ Client │
└────────┬────────┘
↓
┌─────────────────┐
│ Weather API │
└────────┬────────┘
↓
┌─────────────────┐
│ Cache / Redis │
└────────┬────────┘
↓
┌─────────────────┐
│ Weather Service │
└────────┬────────┘
↓
┌─────────────────┐
│ Provider Client │
└────────┬────────┘
↓
┌─────────────────┐
│ Third-Party API │
└─────────────────┘
The key lesson is that integrating a third-party API is not simply about making an HTTP request. A good design creates a layer between our application and the external dependency.
That layer gives us control over security, response formats, validation, retries, timeouts, caching, monitoring, and future provider changes.
Once you understand this pattern, the same architecture can be applied to many real-world integrations, not just weather APIs, but payment gateways, email providers, maps, authentication services, shipping platforms, and many other external systems.
The third-party API provides the data, but our API provides the stability, security, and contract that our application depends on.
Empowering organizations to become ‘data driven’ enterprises with our Cloud experts.
- Reduced infrastructure costs
- Timely data-driven decisions
About CloudThat
FAQs
1. What does "Idempotency"?
ANS: – An API endpoint is idempotent if making the same request multiple times leaves the server in the same state as the first call.
2. Why is it dangerous to put sensitive data in URL parameters?
ANS: – Never put passwords, API keys, or personal information (PII) in a URL (e.g., /api/user?token=secret). The Risk: URLs are routinely stored in plaintext by web browsers, corporate proxy servers, and server log files. Anyone with access to those logs can steal your sensitive tokens. Always pass secrets inside secure HTTPS Request Bodies or Headers.
WRITTEN BY Sonam Kumari
Sonam is a Software Developer at CloudThat with expertise in Python, AWS, and PostgreSQL. A versatile developer, she has experience in building scalable backend systems and data-driven solutions. Skilled in designing APIs, integrating cloud services, and optimizing performance for production-ready applications, Sonam also leverages Amazon QuickSight for analytics and visualization. Passionate about learning and mentoring, she has guided interns and contributed to multiple backend projects. Outside of work, she enjoys traveling, exploring new technologies, and creating content for her Instagram page.
Login

September 7, 2026
PREV
Comments