7. Chapter review

The weather dashboard is the chapter's worked example, but the ideas it builds on generalise. Three-phase construction lets each API layer grow in legible steps. Clean interfaces collapse every failure into a single check against None. Validation gates between layers stop one failure from becoming the next. Separating data retrieval from presentation means the same coordination logic slots under any front end. That shape applies to every multi-API integration you'll touch after this.

The pattern in one paragraph

Each layer subclasses APIClient from Chapter 7, owns one endpoint, and returns either real data or None. The coordinator calls the layers in order and stops the moment anything returns None. Presentation reads the returned data and prints. Nothing about this is specific to weather.

Where this pattern shows up

Anywhere you have sequential dependencies between API calls, the same shape applies:

  • E-commerce checkout: payment authorise, then inventory decrement, then shipping book, with validation between each step so a refund-requiring failure never happens after the shipment went out.
  • Social-media dashboards: authenticate, then fetch profile, then fetch posts, with each layer returning data or None and the coordinator deciding how much to show on partial failure.
  • Travel booking: location search, availability check, pricing, reservation. Four steps, four validation gates, all-or-nothing semantics.
  • Data pipelines: extract, transform, validate, load. Each stage's output is the next stage's input, and any failure short-circuits the rest.

Chapter review quiz

Six questions that work as a self-check. If any of these feel shaky, the corresponding page has the detail:

Select a question to reveal the answer:
Why must geocoding run before the weather API?

The weather API requires latitude and longitude as input, and the only way to get those from a human-friendly city name is through the geocoding service. The order can't be reversed because the weather API has no way to resolve "Dublin" to coordinates on its own. This sequential dependency is what makes a weather dashboard a two-API app in the first place: get_weather_for_city() has to call geocoding, validate the result, and only then call the weather layer.

Why does the coordinator validate lat is None before calling the weather layer?

Without that check, a failed geocoding call passes None values straight into the weather client, which then trips an error inside the API request. The user sees a Python traceback instead of a useful message. The if lat is None gate stops execution at the exact place where the failure is diagnosable: "could not find this city" is obvious here and opaque three layers deeper. This is the fail-fast principle from Chapter 4 applied across module boundaries.

Why do the API layers return None on failure instead of raising exceptions?

Both GeocodingClient.find_location and WeatherClient.get_weather_data return None on failure. Exceptions would force every caller to wrap the call in try/except, and the error-handling surface would grow with every additional layer. Returning None collapses every failure mode into one check. Each layer still handles its own errors internally (the APIClient spine from Chapter 7 does the heavy lifting); what it signals upward is just "data or not."

How do parallel arrays work in the weather API's daily forecast?

The daily section uses one array per field. daily['time'][0], daily['temperature_2m_max'][0], and daily['weather_code'][0] all describe the same day. Index 1 is day two, index 2 is day three. Display code iterates by index rather than navigating nested objects, and bounds-checks every field access because arrays aren't guaranteed to be the same length if the API dropped a day.

Why does KeyboardInterrupt need its own except clause?

Ctrl+C is deliberate, not an error. Catching KeyboardInterrupt separately lets the application print "Goodbye" and exit cleanly instead of dumping a traceback. The pattern is: handle expected-user-action exits at the top of the except chain, handle unknown exceptions at the bottom. Without the separate clause, the generic except Exception wouldn't catch KeyboardInterrupt at all (it inherits from BaseException, not Exception), so the traceback would leak out of the loop and end the session ungracefully.

Why pull formatting into its own helper methods?

Helpers like format_date() and interpret_weather_code() live apart from the display methods because they have one job each. If date formatting needs to respect a locale later, the edit is local. If weather codes need German translations, one lookup table changes. Display code stays focused on layout; formatting logic stays focused on transformations. It's the Single Responsibility Principle applied at method scope, and it makes both pieces independently testable.

Looking forward

The dashboard handles failures gracefully but bluntly: it returns None, prints a message, and expects the user to retry. Production systems need more structure around that. Chapter 9 opens the hood on APIClient: the retry loop, the 429 handling with Retry-After, and the timeout recovery that _make_request hides are patterns you can build from scratch, extend, or apply standalone against libraries that raise exceptions directly. You'll also add two layers APIClient doesn't have, because it hides errors behind a tuple-return interface: a categorizer that labels any exception as user-input, transient, not-found, or unknown, and a message composer that turns those labels into three-part guidance a user can actually act on. These are standalone patterns in Chapter 9, not a subclass of this chapter's code, because the exception-first shape is a deliberate contrast to the tuple-return shape APIClient chose.

Chapters 10 and 11 go deeper on JSON. Chapter 10 covers advanced processing techniques for nested structures, data normalization across different API response shapes, and flexible accessors that tolerate format drift. Chapter 11 introduces schema-based validation that rejects malformed responses at the boundary rather than propagating garbage into your application code.

Everything ahead of you is built on the patterns from this chapter. Progressive construction, clean interfaces, validation gates, separation of concerns -- each new technique adds a layer to this foundation rather than replacing it.