Welcome back!
In Chapter 1, we learned how to get the latest messages. In Chapter 2, we learned how to scroll back in time.
However, both of those chapters assumed everything works perfectly. But in the real world, Wi-Fi drops, servers get overloaded, and cables get unplugged.
In this chapter, we will build the Defensive API Wrapper. This is the safety gear that protects our application when the world goes wrong.
Imagine you need to pick up a package from a warehouse.
The "Do It Yourself" Approach (Bad): You get in your car and drive there.
In programming, "crashing your car" means your application throws an Unhandled Exception. The screen turns white, the app freezes, and the user quits.
The "Defensive Wrapper" Approach (Good): Instead of driving yourself, you hire a Specialized Courier (our wrapper function).
Your application (you) stays safe, comfortable, and stable.
fetchPage
In our project, this courier is a function named fetchPage.
It encapsulates (hides) the raw network client (axios). It acts as a shield between your application logic and the chaotic internet.
Its job is simple: Return data if successful, or return null if anything fails. It never complains, and it never crashes.
Before looking at the code, let's look at the courier's process.
fetchPage for data.fetchPage uses axios (the truck) to try and get it.fetchPage swallows the error.null.
Let's dissect fetchPage in sessionHistory.ts. We will break it down into three small parts to understand the defense mechanisms.
First, we set up the request. We don't just send it blindly; we set rules.
// File: sessionHistory.ts
const resp = await axios
.get<SessionEventsResponse>(ctx.baseUrl, {
headers: ctx.headers, // Authorization (covered in Ch 4)
params, // Pagination (covered in Ch 1 & 2)
timeout: 15000, // Rule 1: Don't wait forever
validateStatus: () => true, // Rule 2: Don't throw on error codes
})
timeout: 15000: If the server takes longer than 15 seconds, we consider it a failure. We don't want the user waiting forever.validateStatus: () => true: By default, axios throws an error if the server says "404 Not Found" or "500 Error." We disable this. We want to receive the error response object so we can inspect it safely, rather than crashing.This is the most important part of the defensive strategy.
// ... continued from above
.catch(() => null) // <--- THE SAFETY NET
axios will fail hard..catch(() => null) block catches network level crashes. If the internet is down, this line turns the catastrophic crash into a harmless null.
Now that we have a response (or null), we check if it is valid before giving it to the app.
// Check if we got a response AND if the status is OK (200)
if (!resp || resp.status !== 200) {
// Log it for the developer, but keeps the app safe
logForDebugging(`[${label}] HTTP ${resp?.status ?? 'error'}`)
return null
}
// If we made it here, we have valid data!
return {
events: Array.isArray(resp.data.data) ? resp.data.data : [],
// ... maps other fields (Covered in Chapter 5) ...
}
if (!resp ...): If the Safety Net (Part 2) triggered, resp is null. We stop here.resp.status !== 200: If the server sent a "500 Server Error", we stop here.return null: The courier returns empty-handed.
You don't usually call fetchPage directly. It is a helper used by the strategies we learned earlier.
Because fetchPage is defensive, our other functions become safe by default.
Example from Chapter 1:
export async function fetchLatestEvents(ctx: HistoryAuthCtx) {
// We delegate the risky work to fetchPage
return fetchPage(ctx, { anchor_to_latest: true }, 'fetchLatestEvents')
}
If fetchLatestEvents returns null, the UI knows something went wrong, but the Javascript keeps running.
You have learned the concept of a Defensive API Wrapper.
By wrapping our raw network calls in fetchPage, we centralized our error handling. We turned "App Crashes" into "Null Returns." This makes the application incredibly stable and resilient to poor network conditions.
Coming Up Next:
We have talked a lot about ctx (the Authorization Context) in these code snippets. How do we actually log in and tell the server who we are?
Next Chapter: Session Authorization Context
Generated by Code IQ