warming up your workspace

Backend Java

Build the backend that frameworks hide: parse raw HTTP by hand, write a JSON parser from scratch, route requests with path parameters, chain middleware, map objects to in-memory tables, pool connections, cache with LRU and TTL, validate request bodies, mint and verify session tokens, and wire it all into a working REST service. The server underneath Spring, from first principles.

11 projects, 275 hands-on levels, run in your browser.

Syllabus

  • Foundations: code through backend servers: Never written code before? Start here. You will learn the basics of Java, methods, variables, types, decisions, loops, and arrays, with simple backend examples. By the end you are ready for Project 1.
  • The HTTP Protocol: Every web framework is, at bottom, a string parser: a browser sends a few lines of text, and the server sends a few lines back. This project builds that text protocol from scratch, splitting a request into method, path, and version, reading headers with case-insensitive lookup, decoding query strings and percent-escapes, mapping status codes to their reason phrases, and assembling a well-formed response. No sockets, just the wire format every backend speaks.
  • A JSON Parser from Scratch: Behind every @RequestBody and res.json() is a parser that turns a stream of characters into a tree of objects. This project builds one: a tokenizer that recognizes strings, numbers, and punctuation; a recursive-descent reader that assembles maps, lists, and scalars; and a serializer that walks the tree back to text with the escaping the spec demands. Once you have written it, JSON stops being magic.
  • Routing: A router is a lookup table from (method, path) to handler. This project builds one from scratch: matching exact paths, extracting path parameters like /users/:id, distinguishing a missing route (404) from a wrong method (405), ordering routes so the most specific wins, and assembling a Router class that dispatches a request to the right handler. The piece of every framework that decides which of your functions runs.
  • Middleware: Between the router and your handler sits a stack of middleware: functions that log, authenticate, parse, compress, and short-circuit. This project builds the chain from scratch, a shared request context, before-and-after hooks, the onion model where each layer wraps the next, auth gates that stop the request early, and a composed pipeline. Once you have written it, app.use() stops being magic.
  • The Repository Layer: Behind every save() and findById() is a data store and a mapping. This project builds a mini-ORM in memory: a table of rows keyed by an auto-incrementing id, full CRUD, mapping rows to and from entity objects, finding by arbitrary fields, and a small query DSL with filtering, sorting, and paging. No database, just the HashMap and the abstractions that make it look like one.
  • Connection Pooling & Rate Limiting: Opening a database connection is expensive, so servers keep a POOL and lend them out. Sending unlimited requests is dangerous, so servers RATE-LIMIT. This project builds both from scratch: a bounded pool with borrow, return, exhaustion, validation, and statistics; and a token-bucket limiter that refills over time. Time and randomness are passed in so everything stays deterministic and testable.
  • Caching: A cache trades memory for speed, and the hard parts are eviction and freshness. This project builds them: an LRU cache that drops the least recently used entry when full, TTL expiry that retires stale entries, the cache-aside pattern that loads on a miss, hit/miss statistics that tell you if the cache is worth it, and ETag conditional responses that skip the body entirely. Time is passed in, so every test is deterministic.
  • Validation & DTOs: A request body arrives as untrusted data; before your handler touches it, it must be validated and bound into a typed object. This project builds that layer: individual constraints (required, range, length, pattern), a validator that collects EVERY violation instead of failing on the first, binding a map into a DTO, and the problem-detail error response that tells the client exactly what went wrong. The boundary between the wild internet and your clean domain.
  • Sessions & Auth: Authentication answers 'who are you?' and authorization answers 'what may you do?'. This project builds both: a signed token (using a simple deterministic hash, a TEACHING stand-in for real HMAC, never use it in production), verification that detects tampering, a session store with expiry, bearer-header extraction, and role and permission checks. The shape of every auth system, with the cryptography deliberately simplified so the structure stays visible.
  • Capstone: A REST Service: Ten projects of machinery, one running service. This capstone assembles a small in-memory user API: a repository holds the data, a router maps requests to handlers, the JSON layer parses bodies and serializes responses, middleware authenticates, and a cache speeds reads. Each chapter wires one more layer, and the finale takes a raw HTTP request string and returns a raw response string, the whole backend you built, end to end.

Key concepts

  • 400 vs 422: 400 Bad Request is for input the server cannot even parse; 422 Unprocessable Entity is for well-formed input that fails validation. The distinction tells the c…
  • 404 vs 405: 404 Not Found means the path does not exist; 405 Method Not Allowed means the path exists but not with this method. A router that conflates them hides useful i…
  • Authentication: Establishing who the caller is, by verifying a credential: a signed token, a session id, a username and password. Answers 'who are you?' before authori…
  • Authorization: Deciding what an authenticated caller may do, via roles, permissions, and ownership. Secure systems deny by default and allow only what is explicitly granted.
  • Backpressure: Signaling upstream to slow down when a system is overloaded, by queueing, rejecting (503), or shedding low-priority work. The alternative to collapsing under l…
  • Bearer token: A token sent in the Authorization: Bearer header; whoever bears it is granted access. The server extracts it, verifies it, and reads the user from its claims.
  • Cache: A fast store of recently computed or fetched values, trading memory for speed. The hard parts are eviction (what to drop when full) and freshness (when to cons…
  • Cache stampede: When a hot key expires and many concurrent requests all miss and hammer the source at once. Single-flight loading (only the first miss loads, others wait) prev…
  • Cache-aside: The dominant caching pattern: check the cache, and on a miss load from the source, store it, and return. Writes invalidate the entry so the next read reloads.…
  • Claim: A statement inside a token's payload, like the user id, roles, or expiry. The server reads claims to make auth decisions after verifying the signature.
  • Conditional request: A request carrying a validator (If-None-Match with an ETag) so the server can answer 304 Not Modified when nothing changed, skipping the body. The protocol-lev…
  • Connection pool: A fixed set of reusable database connections lent out and returned, because opening one per request is slow. Borrow takes a free connection, release returns it…
  • Constraint: A single rule a field must satisfy: not blank, within a range, matching a pattern. Each returns pass or fail with a message; a validator runs many and gathers…
  • Content-Length: The header declaring the body's size in bytes. A well-formed request's body length matches it; servers use it to know where the body ends.
  • Content-Type: The header naming the body's media type, like application/json or text/html; charset=utf-8 . The part before the ; is the media type; the rest are paramete…
  • CRUD: Create, Read, Update, Delete: the four basic operations on a resource, mapping to POST, GET, PUT/PATCH, and DELETE in a REST API. The vocabulary of the reposit…
  • Deny by default: Authorizing nothing unless an allow-list explicitly permits it, so a missing rule fails closed rather than open. The safe default for any access-control system.
  • Dirty checking: Comparing an entity's current fields to its loaded snapshot to find what changed, so the ORM issues an UPDATE only for modified columns. Saves work and avo…
  • DTO: Data Transfer Object: a plain typed object that carries request or response data across a boundary, separate from your domain model. Binding turns an untrusted…
  • Entity mapping: Converting between a database row (a map of columns) and a typed domain object. toRow serializes the object; fromRow reconstructs it. The heart of any ORM.
  • Error boundary: An outer middleware that catches exceptions from inner layers and turns a crash into a clean 500 response. Without it, an uncaught error leaks a stack trace or…
  • Escaping: Replacing characters that would break a format with safe sequences: in JSON, a quote becomes backslash-quote and newline becomes backslash-n. Unescaping revers…
  • ETag: A fingerprint of a response body sent in a header. The client returns it as If-None-Match; if it still matches, the server answers 304 Not Modified with no bod…
  • Fixed window: A rate-limit counter that resets each window (say, per minute). Simple, but allows a burst at the window boundary when two windows' worth of requests clust…
  • Handler: The function a route dispatches to, which reads the request and produces a status and body. Frameworks call it a controller action, view, or endpoint; the rout…
  • Hit ratio: The fraction of cache lookups that find a value: hits / (hits + misses). The single number that says whether a cache is worth its memory; a low ratio means the…
  • HTTP: The text protocol browsers and servers speak: a request (method, path, headers, body) and a response (status, headers, body). Stateless by design, every reques…
  • HTTP header: A Name: value metadata line. Header names are case-insensitive, so Content-Type and content-type are the same header, a detail every parser must honor.
  • HTTP method: The verb naming the intended action: GET (read), POST (create), PUT (replace), PATCH (modify), DELETE (remove). GET, HEAD, and OPTIONS are safe; they must not…
  • Idempotent: An operation that has the same effect whether applied once or many times. PUT and DELETE are idempotent; POST usually is not. The property that makes safe retr…
  • JSON: The dominant data format for web APIs: objects (maps), arrays, strings, numbers, booleans, and null. A parser turns its text into a tree of language objects; a…
  • Keep-alive: HTTP/1.1 reuses one TCP connection for several requests unless the client sends Connection: close . Avoiding a fresh handshake per request is a major performan…
  • LFU eviction: Least Frequently Used: evict the entry with the fewest accesses, rather than the oldest. Better for stable hot sets, worse for shifting access patterns than LR…
  • Load shedding: Deliberately dropping low-priority requests under heavy load so high-priority ones still succeed. A controlled degradation that keeps the critical path alive.
  • LRU eviction: Least Recently Used: when the cache is full, drop the entry untouched for the longest. Tracking access order (often with a linked hash map) keeps hot entries a…
  • Mass-assignment guard: Rejecting request fields the DTO does not declare (like a sneaky isAdmin), so a client cannot set properties you never meant to expose. Strict binding closes t…
  • Middleware: A function in the chain between router and handler that can read, mutate, or short-circuit a request: logging, auth, parsing, compression. Each runs in order o…
  • Onion model: Middleware that wraps the next layer, running code before AND after the handler, like nested shells. The first layer added is the outermost; logging and timing…
  • ORM: Object-Relational Mapping: a layer that maps rows to objects and back, generating queries from method calls. This track builds a mini-ORM in memory to show wha…
  • Pagination: Returning results in pages (skip (page-1)*size, take size) instead of all at once, so a large collection does not overwhelm the client or the server. The LIMIT…
  • Path: The part of the request target identifying the resource, like /users/42 . Split into segments for routing; the part after ? is the query string, not the path.
  • Path parameter: A captured path segment in a route pattern, written :id in /users/:id . Matching binds it to the concrete value, so /users/42 yields id=42 for the handler.
  • Percent-encoding: URL encoding that escapes unsafe characters as %XX hex (and + for space), so hello world travels as hello+world or hello%20world . The server decodes it back.
  • Pool exhaustion: When every pooled connection is in use and a new request cannot borrow one. The pool then queues the waiter or rejects with 503, the backpressure that protects…
  • Problem details (RFC 7807): A machine-readable error body carrying a status, a type URI, and per-field messages, so clients can react programmatically instead of scraping prose. The stand…
  • Query DSL: A chainable, fluent API for building queries, like query.where(...).orderBy(...).limit(...), that an ORM translates into SQL. Each call narrows or shapes the r…
  • Query string: The key-value parameters after ? in a URL, like ?q=java&page=2 . Each value is percent-encoded so special characters survive the trip and must be decoded o…
  • Rate limiting: Capping how many requests a client may make in a time window, to protect the server from overload and abuse. Exceeding the limit returns 429 Too Many Requests…
  • RBAC: Role-Based Access Control: users have roles, roles grant permissions, and a check asks whether any of the user's roles grants the required permission. The…
  • Recursive-descent parsing: Parsing by a set of mutually recursive functions, one per grammar rule: an object parser calls a value parser which may call the object parser again. The natur…
  • Repository: An abstraction over data storage exposing save, find, and delete, hiding whether the rows live in a database or a HashMap. The seam that lets you swap the stor…
  • Request binding: Reading fields from the raw request map into a typed DTO, coercing types (a String "2" to int 2), applying defaults, and rejecting unknown fields. Th…
  • Request context: The object that travels with one request, carrying attributes set by one middleware and read by the next (a parsed user id, the response being built). The shar…
  • Request line: The first line of an HTTP request: METHOD PATH VERSION, for example GET /users HTTP/1.1 . The server parses these three tokens before anything else.
  • Resource: A named thing an API exposes at a URL, like a user or an order. A collection (/users) and its members (/users/42) are both resources, each answering the method…
  • Resource leak: A borrowed connection never returned (often because an exception skipped the release), shrinking the pool until it is empty. The fix is to release in a finally…
  • REST: An architectural style for APIs: resources at URLs, manipulated with HTTP methods, returning representations (usually JSON). GET /users lists, POST /users crea…
  • Route precedence: When several patterns match a path, the most specific wins: a literal beats a parameter, a parameter beats a wildcard. Routers score patterns and check the spe…
  • Routing: Mapping a request's method and path to the handler that serves it. A router matches exact paths and patterns with parameters, picks the most specific when…
  • Safe method: A method that does not change server state: GET, HEAD, OPTIONS. Caches and crawlers rely on this guarantee, which is why side effects must never hide behind a…
  • Sanitization: Normalizing accepted input rather than rejecting it: trim whitespace, lowercase emails, strip control characters, escape HTML. Cleans data before it reaches th…
  • Serialization: Turning in-memory objects back into a transmittable string, escaping strings and formatting numbers per the spec. The inverse of parsing; a correct pair round-…
  • Service facade: One class presenting a clean API over the whole stack, wiring repository, router, JSON, middleware, and cache behind a single entry point. Callers hand it a re…
  • Session: Server-side auth state: a session id (in a cookie) maps to stored user data, with creation, expiry, and revocation. The stateful alternative to self-contained…
  • Short-circuiting: A middleware halting the chain before the handler runs, as an auth gate does on a missing token (401) or a rate limiter on too many requests (429). A halt flag…
  • Signed token: A self-contained credential carrying a payload and a signature, so the server can trust it without storing state. Verification re-signs the payload and compare…
  • Sliding window: A rate limiter that counts requests in the last N seconds from now, rather than a fixed calendar window. Smoother than fixed windows, at the cost of tracking r…
  • Stale-while-revalidate: A freshness policy that serves a slightly-expired entry immediately while refreshing it in the background, trading perfect freshness for low latency. Common in…
  • Stateless server: A server that keeps no per-client memory between requests, putting all needed state in the request itself (a token) or a shared store. Statelessness is what le…
  • Status code: The three-digit result of a request, grouped by first digit: 2xx success, 3xx redirect, 4xx client error, 5xx server error. Each pairs with a reason phrase lik…
  • Token bucket: A rate-limit algorithm: a bucket holds tokens, each request spends one, and tokens refill at a steady rate up to a capacity. Allows short bursts (up to capacit…
  • Token expiry: An exp claim after which a token is no longer valid, limiting the damage of a leaked credential. A small clock-skew grace and a refresh window handle real-worl…
  • Tokenizer: The first stage of a parser: it scans characters and groups them into tokens (strings, numbers, punctuation), classifying each by its first character. The pars…
  • TTL (time to live): An expiry stamped on a cache entry; after it, the entry is stale and treated as a miss. Sliding TTL extends the life on each access; a grace period enables ser…
  • Upsert: Insert-or-update by a natural key: if a row with that key exists, update it; otherwise insert. One operation where two would otherwise race.
  • Validation: Checking request data against constraints (required, range, length, pattern) before the handler trusts it. Good validators collect EVERY violation, not just th…
  • Wait queue: A FIFO line of requests waiting for a free pooled resource. When a connection is released, the first waiter is handed it, bounding how long any request waits.
  • Wildcard route: A pattern segment ( * ) that matches anything, used for catch-all routes like static file serving. Less specific than a literal or a parameter, so it loses pre…
  • Write-through: A write that updates the cache AND the source together, keeping them consistent at the cost of a slower write. Contrast write-around, which writes the source a…