REST APIs Through Rugby Systems Thinking

Search for a command to run...

No comments yet. Be the first to comment.
This guide was initially generated using AI. Rather than writing every sentence from scratch, I used AI as a research, drafting and teaching assistant to help produce a comprehensive first draft. The

Modern dev environments rely heavily on third-party extensions. Many of these extensions execute code locally and may have access to source code, config files, credentials, and other sensitive data. A

A fresh Ubuntu installation is designed to be permissive, catering equally to desktop, server, and container workloads without assuming a strict security model. However, the moment a system is exposed

Developing software locally is only one part of the job. Systems must also operate reliably in production, handle failures, and remain maintainable as requirements change. A backend should be understa

Modern software systems power nearly every aspect of business operations, from banking platforms and healthcare systems to cloud infrastructure, e-commerce applications, and enterprise automation. As

In South African rugby, coordination only works because every participant operates within defined rules. Cheslin Kolbe finishing a counter-attack, Damian Willemse shifting between positions, or Kurt-Lee Arendse exploiting space all depend on shared structure: set phases, agreed signals, and predictable outcomes.
REST APIs operate on the same principle. Systems interact reliably because the rules of communication are strict and well-defined. Once those rules are understood, the system stops looking chaotic.
An API (Application Programming Interface) is a formal contract between systems.
It defines:
How requests must be structured
What responses will look like
What operations are permitted
If the request follows the contract, the system responds predictably. If it doesn’t, the request fails early.
This is about a stable interface exposed to consumers.
REST (Representational State Transfer) is a set of constraints for designing APIs over HTTP.
It standardises interaction around:
Resources (things you operate on)
Uniform operations (HTTP methods)
Stateless communication
Because it uses HTTP, it inherits a widely understood transport mechanism already used by browsers and networks.
APIs are also classified by who can access them:
Public APIs – open to external consumers with documentation and keys
Private APIs – internal system-to-system communication
Partner APIs – restricted access for approved external organisations
This classification is about governance and not technical design.
REST models everything as a resource: a player, a match, or a tournament.
URI (Uniform Resource Identifier)
A URI identifies a resource.
Example:
player/911
It is an identifier only. It doesn't define access.
A URI identifies something but doesn’t tell you where or how to access it.
A URL identifies and locates the resource over a network.
Example:
https://tech-journeys.com/players/kolbe
This URL identifies Cheslin Kolbe and also tells your system to fetch his data via HTTPS from this exact location.
All URLs are URIs because they identify a resource, but not all URIs are URLs.
URI: identifies a resource (who/what)
URL: identifies a resource and tells you how to locate it (who/what + where/how)
Relationship: Every URL is a URI, but not every URI is a URL.
Here’s an example written in Python:
# Define a list of players (unique identifiers in the system)
player_uris = [
"players/kolbe",
"players/smith",
"players/duplessis",
"players/mapimpi"
]
# Base URL of our rugby API or website
base_url = "https://tech-journeys.com/"
# Loop through each player and generate their full URL
for uri in player_uris:
player_url = f"{base_url}{uri}"
print("Player URI:", uri)
print("Player URL:", player_url)
print("-" * 40) # separator for readability
REST defines standard actions via HTTP methods.
A GET request asks the server for information without changing anything.
import requests
# Get Cheslin Kolbe's stats
response = requests.get("https://tech-journeys.com/players/kolbe") #This URL doesn't really exist :)
player_data = response.json()
print(player_data)
{
"name": "Cheslin Kolbe",
"team": "South Africa",
"position": "Wing",
"special_move": "Ankle Breaker",
"world_cups": [2019, 2023]
}
A POST request sends new information to the server to create something that does not yet exist like adding a new player to the squad.
new_player = {
"name": "Canan Moodie",
"team": "South Africa",
"position": "Centre",
"world_cups": [2023]
}
response = requests.post("https://tech-journeys.com/players", json=new_player)
print(response.status_code) # 201 means created
A PUT request replaces or updates an existing resource. For example, updating a player’s position after a tactical change.
updated_position = {
"position": "Fullback"
}
response = requests.put("https://tech-journeys.com/players/kolbe", json=updated_position)
print(response.status_code) # 200 means success
A DELETE request removes a resource completely.
response = requests.delete("https://tech-journeys.com/players/retired_player_id")
print(response.status_code) # 204 means no content, successfully deleted
A REST system typically follows a simple flow:
Client → API Server → Database
Client: browser, mobile app, or script
API Server: request validation, routing, business logic
Database: persistent storage of resources
The API server enforces rules and isolates clients from internal complexity.
APIs exchange data using JSON (JavaScript Object Notation).
Example of a player in JSON:
{
"name": "Cheslin Kolbe",
"team": "South Africa",
"position": "Wing",
"special_move": "Ankle Breaker",
"world_cups": [2019, 2023]
}
It is structured as key-value pairs and arrays, optimised for machine parsing and human readability.
APIs expose controlled entry points to systems. Without controls, they become attack surfaces.
Confirms who is making the request.
Example:
import requests
headers = {"Authorization": "Bearer YOUR_JWT_TOKEN"}
response = requests.get("https://tech-journeys.com/players/kolbe", headers=headers)
print(response.json())
Common mechanisms:
API keys
JWT (JSON Web Tokens)
Determines what the authenticated identity is allowed to do. Identity alone is insufficient.
HTTPS enforces TLS encryption between client and server. This prevents interception or tampering in transit.
APIs enforce request thresholds (e.g., 100 requests/minute) to protect infrastructure from overload and denial-of-service patterns.
REST becomes simpler when reduced to state transitions:
GET → observe state
POST → create state
PUT → modify state
DELETE → remove state
Everything else is implementation detail around those transitions.
Over time, I’ve learned that most systems only feel complex until you relate them to something familiar. Once you do that, the moving parts become easier to reason about.
A GET request is just observing state.
A POST request is introducing change.
Access control is no different from checking permissions at a gate.
The specific analogy doesn’t matter. It could be rugby, football, baking, or fixing cars. What matters is mapping abstract behaviour to something you already understand.
That shift in thinking turns technical concepts into something more durable. Instead of memorising terminology, you recognise patterns. And once you recognise the pattern, it’s much easier to apply it when you’re building or debugging real systems.