Skip to main content

ikwukao

Back to Journal

Engineering Journal

Caching API Responses in PokedexCLI: Reducing Network Work in Go

Exploring the role of an in-memory cache in PokedexCLI, including cache keys, expiration, memory trade-offs, and how caching changes the application's interaction with an external API.

5 min read Go, Golang, Caching, HTTP, PokedexCLI, Performance, Backend Engineering, API Design

Caching API Responses in PokedexCLI: Reducing Network Work in Go

One of the easiest performance problems to overlook in an API-driven application is repeated work.

If an application repeatedly requests the same resource from a remote service, every request introduces network latency and another dependency on the availability of that service.

PokedexCLI provides a useful environment for exploring this problem because the application repeatedly interacts with the Pokémon API while the user navigates locations and explores areas.

A small in-memory cache can significantly change that interaction.

The Problem With Repeated Requests

Without caching, the flow is straightforward:

CLI
HTTP request
Pokémon API
Response

If the same resource is requested again, the entire process happens again.

That means the application pays the network cost repeatedly.

A cache introduces another decision point:

CLI
Cache
 ├── Hit ─────► Return stored response
 └── Miss
      API
    Response
     Cache

The application now has an opportunity to avoid unnecessary network work.

What Is a Cache?

At its simplest, a cache stores previously retrieved data so it can be reused later.

For PokedexCLI, an in-memory cache can associate a resource identifier with the response bytes.

Conceptually:

Key                         Value
-----------------------------------------
/location-area/1/           response bytes
/location-area/2/           response bytes
/pokemon/pikachu            response bytes

When the same key appears again, the application can retrieve the stored value instead of contacting the API.

Choosing a Cache Key

A cache is only useful if requests can be mapped consistently to stored entries.

The requested URL is a natural cache key.

For example:

https://pokeapi.co/api/v2/location-area/1/

can uniquely identify a resource.

Using the request URL as the key also keeps the cache independent of the specific command that requested the data.

That means different parts of the application can benefit from the same cached resource.

Cache Hits and Misses

Every cache lookup produces one of two important outcomes.

Cache hit

The requested resource already exists.

Request
Cache
Found
Return data

No network request is required.

Cache miss

The requested resource is not currently cached.

Request
Cache
Not found
API request
Store response
Return data

This distinction is fundamental to cache design.

Why In-Memory Caching Works Well Here

PokedexCLI does not need a distributed cache.

It is a local command-line application.

An in-memory cache is therefore attractive because it is:

  • simple;
  • fast;
  • easy to integrate;
  • inexpensive;
  • independent of external infrastructure.

There is no Redis server to configure.

There is no database to maintain.

The cache exists only for the lifetime of the application process.

That is an appropriate trade-off for the problem.

Expiration and Stale Data

Caching introduces an important question:

How long should cached data remain valid?

A cache without expiration can eventually contain stale information.

An expiration policy associates cached data with a timestamp.

Conceptually:

Cache Entry
 ├── value
 └── expiration time

A lookup can then determine:

Is entry present?
      ├── No → cache miss
      └── Yes
           ├── Fresh → cache hit
           └── Expired → cache miss

For relatively stable API resources, a short expiration period can provide a useful balance between freshness and reduced network traffic.

Cache Lifetime

An in-memory cache has another important characteristic: process lifetime.

When the CLI exits:

Application exits
Memory released
Cache disappears

That is not necessarily a problem.

The goal of this cache is not permanent persistence.

It is to reduce redundant work during an active session.

This is a good example of matching infrastructure complexity to actual requirements.

Caching Is a Trade-Off

Caching is not automatically beneficial.

It introduces memory usage and consistency concerns.

The application must now answer:

  • What should be cached?
  • How long should it remain valid?
  • What happens when it expires?
  • How much memory can the cache consume?
  • What happens if cached data is incorrect?

These are architecture questions rather than implementation details.

Performance Implications

Network requests are comparatively expensive.

A cache hit can avoid:

  • DNS resolution;
  • connection setup;
  • network transmission;
  • server processing;
  • response transfer;
  • JSON decoding work.

The actual savings depend on the environment, but the principle is simple:

Cache hit
Less network work
Lower latency
Better interactive experience

For a CLI, responsiveness matters because the user experiences every request directly.

Caching and User Experience

Consider repeatedly exploring the same location.

Without caching:

User command
Network request
Wait
Response

With caching:

User command
Cache lookup
Immediate response

The architecture has therefore improved not only performance but also the interaction model.

Keeping the Cache Independent

The cache should not become tightly coupled to command implementations.

A command should not need to understand the internal representation of cache entries.

Instead:

Command
API Client
Cache

The API client can coordinate cache lookup and network retrieval.

This keeps caching as an implementation detail of data retrieval rather than a concern of every command.

Caching and Testing

Caching also introduces useful testing scenarios.

A cache implementation can be tested for:

  • successful insertion;
  • successful retrieval;
  • missing keys;
  • expiration;
  • replacement;
  • repeated access.

The application can also verify an important behavioral property:

First request  → network
Second request → cache

That makes caching behavior observable and testable.

What Caching Taught Me

The most important lesson is that performance optimization begins with understanding repeated work.

It is easy to reach for complicated infrastructure.

But PokedexCLI demonstrates that a small, local cache can solve a very specific problem without introducing unnecessary operational complexity.

The solution matches the requirements.

That is an important engineering habit.

Final Thoughts

Caching is one of those concepts that appears simple until consistency, expiration, memory, and invalidation become important.

PokedexCLI offers a useful introduction to those trade-offs.

The project does not need a distributed caching layer.

It needs a lightweight mechanism that prevents redundant API requests during an interactive session.

That is exactly where an in-memory cache fits.

The broader lesson extends to backend systems:

Good infrastructure is not the infrastructure with the most components. It is the infrastructure that solves the actual problem with an appropriate level of complexity.


  • In-memory caching
  • HTTP caching
  • Go backend performance
  • Cache expiration
  • API optimization
  • Network latency
  • Backend architecture

ikwukao

Backend • Distributed Systems • Platform Engineering

I design and build reliable backend systems, distributed platforms, cloud-native infrastructure, and developer tooling with Go, Python, Linux, Kubernetes, and modern DevOps practices.

Building reliable systems from Nigeria · GMT+1

Explore

Connect

© 2026 Ikwuka Okoye. All rights reserved.

Built with Hugo, Tailwind CSS & Go-inspired simplicity.