Rick & Morty

Rick and Morty cast
Zero auth
REST + GraphQL
Free & public
Container-ready
826+
Characters
42
API Pages
3
Services
0
API Keys

The ground-floor reference implementation for the k3s-pi5 DevOps learning platform — a complete three-tier architecture pairing a Node.js frontend, a .NET API gateway, and a PostgreSQL database.

Everything below is an encyclopedia entry for this reference stack — the why behind the API choice, the architecture, the three progressive scenarios, and the patterns that recur throughout the curriculum. Expand any section to dig in.

Every DevOps curriculum needs a sample application — something real enough to demonstrate production patterns, but simple enough that the infrastructure stays the focus, not the app logic. The Rick and Morty API hits a rare sweet spot.

What makes it ideal for a learning platform

PropertyWhy it matters
Free & public No API keys, no billing, no sign-up. Focus on architecture, not credential management. Every example is reproducible without registering for anything.
REST + GraphQL Teaches both paradigms. The reference uses REST for simplicity, with GraphQL as a natural extension.
Stable data Production ended in 2022 — canonical, no drift, no breaking changes. Perfect for caching demos and CI/CD integration tests.
Predictable paging 20 results per page, 42 pages of characters. Ideal for demonstrating pagination and resilient HTTP clients.
Relational data Characters link to episodes, locations have residents, episodes have cast lists — a natural fit for SQL joins, junction tables, and full-text search.
Memorable DevOps docs are often dry. The Rick and Morty framing gives every component a personality — Rick is the .NET layer, Morty the Node.js frontend, the garage is PostgreSQL.

What this is not

  • Not a production app. A reference architecture for learning — it demonstrates production patterns but stays intentionally minimal.
  • Not a fan site. The show is the theme, not the product. The product is the infrastructure patterns.
  • Not the only sample. This is the first reference; later modules add sample apps that build on the same patterns.

The reference implements a 3-tier architecture with a .NET API gateway as the central orchestrator. Every data request from the frontend passes through the .NET layer — never directly to the upstream API or the database.

┌─────────────────────────────────────────────┐ │ Rick and Morty API │ │ rickandmortyapi.com/api │ └──────────────────┬──────────────────────────┘ │ HTTPS ▼ ┌─────────────────────────────────────────────┐ │ .NET API Gateway (VM2 / k3s Deployment) │ │ │ │ • Rate-limited (100 req/min per IP) │ │ • Cache-aside pattern (Postgres L2) │ │ • Health + metrics endpoints │ └────────┬───────────────────┬────────────────┘ │ HTTP (internal) │ TCP 5432 ▼ ▼ ┌──────────────────┐ ┌───────────────────────┐ │ Node.js Frontend│ │ PostgreSQL (VM3 / │ │ (React/Next.js) │ │ k3s StatefulSet) │ │ Port 3000 │ │ Port 5432 │ └──────────────────┘ └───────────────────────┘

Key architectural decisions

DecisionRationale
.NET as orchestrator The author's primary stack is .NET/C#. The gateway pattern maps cleanly to ASP.NET Core middleware — caching, rate limiting, auth, and logging are all first-class concerns. The same patterns work in Express, Go, or Python; .NET is the example, not the requirement.
PostgreSQL over SQLite SQLite is simpler but teaches nothing about connection strings, network isolation, or persistent volumes — exactly the skills you need for Kubernetes StatefulSets.
Node.js frontend, not Blazor A polyglot stack demonstrates cross-service communication. The Node app must handle HTTP clients, errors, and retries — universal skills independent of language.
Cache-aside, not write-through The data is read-heavy and changes rarely. Cache-aside (check → miss → fetch → store → return) is the simplest pattern that still teaches invalidation and TTL management.
Fixed-window rate limiter Simple to grasp, built into .NET 8 with zero extra packages, and produces clear 429s with Retry-After headers. Token-bucket would be more precise but adds complexity without learning value here.

The reference is presented as three progressive scenarios. Each adds a layer without removing the previous one — you see why each layer exists before it's introduced.

Scenario A
Direct Fetch — no cache

VM2 proxies straight to the upstream API. Teaches HTTP client basics, JSON deserialization, and API proxying. Best for local dev and freshness-critical demos.

Scenario B
.NET Proxy + Postgres cache

Cache-aside with PostgreSQL as an L2 store. Teaches TTL management, connection pooling, and reducing upstream calls. The production-like default.

Scenario C
Containerized on k3s

Each VM maps to a Kubernetes resource — Deployments, Services, Ingress, StatefulSets, PVCs, NetworkPolicies. The target architecture for everything beyond local dev.

The pedagogical thread

Scenario A is the "hello world" — it proves connectivity. Scenario B adds caching and introduces the database. Scenario C maps the whole thing to Kubernetes. Each step is small enough to understand in isolation, but together they cover the full journey from localhost to a production-shaped homelab cluster.

Every pattern in this reference recurs in later k3s-pi5 modules. Understanding them here means you recognise them everywhere.

1. Cache-Aside Pattern

Client → API → Cache? ──hit──→ return cached
                    │
                   miss
                    │
                    ▼
              Upstream API → Store in cache → return

Where it recurs: M2 Docker Compose (.NET + Redis), M3 Sample Apps (Node.js + Postgres on k3s).

2. Rate Limiting (Fixed Window)

Request → RateLimiter middleware
              │
              ├─ within limit → controller action
              │
              └─ exceeded → 429 Too Many Requests + Retry-After header

Where it recurs: M3 Security (NetworkPolicies + RBAC), M4 Observability (Prometheus metrics on 429 counts).

3. Health + Metrics Endpoints (un-rate-limited)

GET /health   → { "status": "healthy" }           ← k8s liveness/readiness
GET /metrics  → { "requests_served": 1423, ... }   ← Prometheus scrape

Where it recurs: Every module that deploys to k3s. M4 Observability replaces the stub with real Prometheus metrics.

4. Environment-Driven Configuration

Every tunable — cache TTL, rate-limit threshold, connection string — is an environment variable. No magic numbers in code. This convention is non-negotiable and enforced across every k3s-pi5 module.

The .NET API enforces rate limiting using ASP.NET Core 8's built-in System.Threading.RateLimiting — zero extra NuGet packages.

Why it matters in this project

  • Protects the upstream API. The Rick and Morty API has no auth and no documented rate limit. Being a good API citizen means self-throttling.
  • Prevents runaway frontends. A buggy React effect loop could fire thousands of requests; the limiter catches it at the gateway before it reaches the DB or upstream.
  • Demonstrates middleware composition. Rate limiting is early in the pipeline — it shows how ASP.NET Core middleware order matters: auth, rate limiting, caching, then the controller.

Policy design

PolicyLimitWindowQueueApplies to
fixed 100 requests 60 seconds 0 (reject immediately) All /api/* endpoints
none Disabled via [DisableRateLimiting] /health, /metrics

Health and metrics endpoints are deliberately excluded — Kubernetes probes fire every 10 seconds and Prometheus scrapes every 15 seconds; throttling either would trigger false-positive pod restarts.

Full implementation: see the .NET Proxy Controller section in the README.

This tracker is the canonical source of truth for iteration progress. Completed items move to Done, and their stable content lives in the README.

#ItemStatusNotes
1Scenario A — Direct Fetch✅ DonePassthrough proxy, zero DB dependency
2Scenario B — .NET Proxy + PostgreSQL Cache✅ DoneCache-aside pattern, configurable TTL
3Scenario C — Containerized on k3s✅ DoneVMs → Kubernetes mapping
4Rate limiter on .NET API✅ DoneFixed-window, 100 req/min per IP
5Docker Compose quick-start✅ DoneSingle-command local dev
6Monitoring & backups✅ DoneHealth checks, pg_dump cron
7Curriculum mapping✅ DoneREADME concepts → site modules
8CI/CD pipeline (Jenkins)✅ DoneSelf-hosted on Vagrant VMs (master + agents)
9Config management (Ansible)✅ DoneAgentless playbooks deploy the apps
10Monitoring (Nagios Core)✅ DoneCheck-based monitoring + alerting
11Cloud reach (AWS free tier)✅ DoneEC2, IAM + CLI, ECS
12Add Redis L1 cache⏳ PlannedSub-millisecond cache layer
13Auth (JWT + API keys)⏳ PlannedProtect VM2 endpoints
14Observability (Prometheus + Grafana + Loki)🔭 OptionalRicher metrics/logs/dashboards
15Infrastructure as Code (Terraform)🔭 OptionalProvision cloud resources declaratively
16GitOps (ArgoCD or Flux)🔭 OptionalApp-of-apps; reconcile from Git

This reference is the first concrete example in the k3s-pi5 learning platform. Every concept here maps to one or more curriculum modules:

Reference conceptk3s-pi5 module(s)What you learn
VM provisioning (VM1/2/3)Virtual Machines & ProvisioningVagrant, Parallels/VMware, Ansible
Manual service startupDevOps IntroThe "before containers" baseline
Docker ComposeStandalone ContainersDockerfiles, multi-stage builds, Compose
.NET API + PostgreSQLSample Apps (k3s)ConfigMaps, Secrets, Ingress on k3s
PostgreSQL schema + PVCPersistent StorageStatefulSets, PVCs, storage classes
Rate limitingSecurityNetworkPolicies, RBAC, Secrets rotation
Health checks + metricsMonitoring (Nagios Core)Check-based monitoring + alerting
Scenario C (k3s)K3s on Pi 5Cluster setup, Cloudflare Tunnel, cert-manager
Build → test → deployCI/CD (Jenkins)Self-hosted pipelines on Vagrant VMs
Cloud reachCloud (AWS, free tier)EC2, IAM + CLI, ECS

Recommended learning path

  1. Read this encyclopedia page — understand the architecture, decisions, and patterns.
  2. Read the README — study the full code, env vars, and deployment options.
  3. Follow the k3s-pi5 modules in order on the main site.
  4. Return here whenever you meet a pattern you recognise — cache-aside, rate limiting, health checks — and see how it fits the larger architecture.

The Rick and Morty framing isn't just decorative — it gives every component a personality that makes the stack easier to reason about.

Rick Sanchez.NET API

Hyper-intelligent, does the heavy lifting, owns the logic, talks to the outside world. Builds portal guns from scrap — like a well-factored middleware pipeline.

Morty SmithNode.js UI

What users actually see. Anxious but functional, inseparable from Rick — the frontend can't work without the API. His brainwaves simplify Rick's genius for human consumption.

The GaragePostgreSQL

Where everything is stored between adventures. Messy but contains every artifact from every timeline — like a database with full history and full-text search.

Portal GunHTTP / REST

Instant transport between dimensions — like an API call that fetches data from any endpoint in the universe.

Council of Ricksk3s Cluster

Many Ricks coordinating across dimensions — each autonomous but governed by shared rules, like pods managed by the control plane.

"Nobody exists on purpose. Nobody belongs anywhere. Everybody's gonna die. Come deploy Kubernetes." — Rick Sanchez, probably