Web Resource Caching: Server-Side

The subject of Web resource caching is as old as the World Wide Web itself. However, I'd like to offer an as-exhaustive-as-possible catalogue of how one can improve performance by caching. Web resource caching can happen in two different places: client-side - on the browser and server-side. In the previous post, I explained the former; this post focuses on the latter.

While client-side caching works well, it has one central issue: to serve the resource locally, it must first have it in the cache. Thus, each client needs its cached resource. If the requested resource is intensive to compute, it doesn't scale. The idea behind server-side caching is to compute the resource once and serve it from the cache to all clients.

Web Resource Caching: Client-Side

The subject of Web resource caching is as old as the World Wide Web itself. However, I'd like to offer an as-exhaustive-as-possible catalogue of how one can improve performance by caching. Web resource caching can happen in two different places: client-side - on the browser and server-side. This post is dedicated to the former; the next post will focus on the latter.

Caching 101

The idea behind caching is simple: if a resource is time- or resource-consuming to compute, do it once and store the result. When somebody requests the resource afterwards, return the stored result instead of computing it a second time. It looks simple - and it is, but the devil is in the detail, as they say.

A Poor Man’s API

Creating a full-fledged API requires resources, both time and money. You need to think about the model, the design, the REST principles, etc., without writing a single line of code. Most of the time, you don't know whether it's worth it: you'd like to offer a Minimum Viable Product and iterate from there. I want to show how you can achieve it without writing a single line of code.

The Solution

The main requirement of the solution is to use the PostgreSQL database. It's a well-established Open Source SQL database.

Spring Modulith: Have We Reached Modularity Maturity?

One of the main reasons to design microservices is that they enforce strong module boundaries. However, the cons of microservices are so huge that it's like chopping off your right hand to learn to write with the left one; there are more manageable (and less painful!) ways to achieve the same result.

Even since the microservices craze started, some cooler heads have prevailed. In particular, Oliver Drotbohm, a developer on the Spring framework, has been a long-time proponent of the moduliths alternative. The idea is to keep a monolith but design it around modules.

Geo-Routing with Apache APISIX

Apache APISIX, the Apache-led API Gateway, comes out of the box with many plugins to implement your use case. Sometimes, however, the plugin you're looking for is not available. While creating your own is always possible, it's sometimes necessary. Today, I'll show you how to route users according to their location without writing a single line of Lua code.

Why Geo-Routing?

Geo-routing is to forward HTTP requests based on a user's physical location, inferred from their IP. There are many reasons to do that, and here is a couple of them.

Structured Error Messages for HTTP APIs

Ever since I started to work on the Apache APISIX project, I've been trying to improve my knowledge and understanding of REST RESTful HTTP APIs. For this, I'm reading and watching the following sources:

  • Books: At the moment, I'm finishing API Design Patterns. Expect a review soon.
  • YouTube: I'd recommend Erik Wilde's channel. While some videos are better than others, they all focus on APIs.
  • IETF RFCs: Most RFCs are not about APIs, but a friendly person compiled a list of the ones that are.

Today, I'd like to introduce the "Problem Details for HTTP APIs" RFC, aka, RFC 7807.

Discuss the Problem, Not the Solution

As a tech guy, I love to discuss technologies. And as discussions go, it's generally the comparison kind: JVM vs. Net, Java vs. Kotlin, Go vs. Rust, Maven vs. the unspeakable one, etc. However, it's too easy to fall into the quagmire of the merits and flaws of our beloved toys, talk about them for hours, and not reach a satisfactory agreement.

A couple of years ago, I worked as a "Solution Architect". The job has different titles, e.g., Solution Designer, and Solution Engineer, but the goal is always the same: find the "best" solution for a problem, most of the time, a business problem.

Exceptions in Lambdas

Java introduced the concept of checked exceptions. The idea of forcing developers to manage exceptions was revolutionary compared to the earlier approaches.

Nowadays, Java remains the only widespread language to offer checked exceptions. For example, every exception in Kotlin is unchecked.

Different Test Scopes in Rust

I'm still working on learning Rust. Beyond syntax, learning a language requires familiarizing oneself with its idioms and ecosystem. I'm at a point where I want to explore testing in Rust.

The Initial Problem

We have used Dependency Injection a lot - for ages on the JVM. Even if you're not using a framework, Dependency Injection helps decouple components. Here's a basic example:

Rewriting the Apache APISIX Response-rewrite Plugin in Rust

Last week, I described the basics of how to develop and deploy a Rust plugin for Apache APISIX. The plugin just logged a message when it received the request. Today, I want to leverage what we learned to create something more valuable: write part of the response-rewrite plugin with Rust.

Adding a Hard-coded Header

Let's start small and add a hard-coded response header. Last week, we used the on_http_request_headers() function. The proxy_wasm specification defines several function hooks for each step in a request-response lifecycle:

Apache APISIX Loves Rust! (And Me, Too)

Apache APISIX is built upon the shoulders of two giants:

  • NGINX, a widespread open source reverse-proxy
  • OpenResty, a platform that allows scripting NGINX with the Lua programming language via LuaJIT

This approach allows APISIX to provide out-of-the-box Lua plugins that should fit most business requirements. But there always comes a time when generic plugins don't fit your requirements. In this case, you can write your own Lua plugin.

The Maze of Python Dependency Management

For over 20 years, I've developed code for the JVM, first in Java, then in Kotlin. However, the JVM is not a silver bullet, e.g., in scripts:

  1. Virtual machines incur additional memory requirements
  2. In many cases, the script doesn't run long enough to gain any benefit performance-wise. The bytecode is interpreted and never compiles to native code.

For these reasons, I now write my scripts in Python. One of them collects social media metrics from different sources and stores them in BigQuery for analytics.

A Quick Glance at the Kubernetes Gateway API

In one of my recent blog posts, I described several ways to access Kubernetes pods. One can access a pod through its IP, but pods are naturally transient. The nominal way is to configure a Service: its IP is stable, and Kubernetes' job is to keep the mapping between a Service and its underlying pods up-to-date. Different kinds of services are available: internal only, NodePort to finally allow access from outside the cluster, and LoadBalancer that relies on a third-party component - in general, a cloud provider one. Finally, I mentioned the Ingress object, which also allows routing.

I deliberately left out the new kid on the block, the Gateway API. It's the subject of this post.

End-to-End Tracing With OpenTelemetry

Whether you implement microservices or not (and you probably shouldn't), your system is most probably composed of multiple components. The most straightforward system is probably made of a reverse proxy, an app, and a database. In this case, monitoring is not only a good idea, it's a requirement. The higher the number of components through which a request may flow, the strongest the requirement.

However, monitoring is only the beginning of the journey. When requests start to fail en masse, you need an aggregated view across all components. It's called tracing, and it's one of the pillars of observability. The other two are metrics and logs.

Renovate, a Dependabot Alternative

I won't introduce Dependabot. Lots and lots of developers use it daily on GitHub. I do use it as well. However, it suffers from two drawbacks:

  • While it's perfectly integrated with GitHub, integrations with other platforms are less seamless.
  • It's limited in the list of ecosystems it supports For example, I generally use Docker Compose files for my demos. When necessary, I use Kubernetes. Dependabot supports none.

Backend-for-Frontend: The Demo

In one of my earlier posts, I described the Backend-for-Frontend pattern. In short, it offers a single facade over multiple backend parts. Moreover, it provides each client type, e.g. desktop, mobile, exactly the data that it needs and not more in the format required by this client type.

The Use-case

Imagine the following use case. In an e-commerce shop, the home page should display multiple unrelated data at once.

On Cosmetics vs. Intrinsics in Programming

A ruthless battle occurs every day on the World Wide Web. Its goal is to decide which programming flavor is the best: OOP or FP? I assume that imperative and procedural programming are not part of the contenders.

Arguments range from the factual to the irrelevant to the utterly stupid. A couple of years ago, I wanted to listen to a video of Martin Odersky (of Scala fame). I remember neither the exact talk nor the subject. What I remember is the introduction, though: he explained that FP was more popular than OOP... because there were many more conferences dedicated to the former than to the latter.

Discussing Backend for Front-end

In the good old days, applications were simple. A browser sent a request to a web app endpoint; the latter fetched data from a database and returned the response.

The rise of mobile clients and integrations with other apps upset this simplicity. I want to discuss one solution to handle the complexity in this post.