REST APIs Through Rugby Systems Thinking

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.
What is a REST API?
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 as an Architectural Style
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.
API Types (Access Model, Not Behaviour)
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.
Resources, URIs, and URLs
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.
URL (Uniform Resource Locator)
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.
Quick Rule of Thumb
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.
Rugby Analogy Summary
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
Output
HTTP Methods as System Operations
REST defines standard actions via HTTP methods.
GET – Read State
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)
Output
{
"name": "Cheslin Kolbe",
"team": "South Africa",
"position": "Wing",
"special_move": "Ankle Breaker",
"world_cups": [2019, 2023]
}
POST – Create Resource
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
PUT – Updating Resource
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
DELETE — Remove Resource
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 Simple System Design View
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.
Data Format: JSON
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.
Security Model
APIs expose controlled entry points to systems. Without controls, they become attack surfaces.
Authentication (Identity)
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)
Authorisation (Permissions)
Determines what the authenticated identity is allowed to do. Identity alone is insufficient.
Encryption (Transport Security)
HTTPS enforces TLS encryption between client and server. This prevents interception or tampering in transit.
Rate Limiting (Abuse Control)
APIs enforce request thresholds (e.g., 100 requests/minute) to protect infrastructure from overload and denial-of-service patterns.
Core Mental Model
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.
My approach to complex systems
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.






