Every URL we shorten still maps to the same hardcoded abc123. In this chapter we replace that fake with a real short-code generator and make sure no two URLs ever get the same code. The catch is that random generators are normally hard to test, so we design ours to be predictable on demand.

Three terms carry this chapter. The codes themselves are base62: built from a 62-character alphabet (0-9, then A-Z, then a-z) with no symbols or punctuation, so a code drops cleanly into a link with nothing to URL-encode.
Collision. Two different URLs assigned the same short code, so the second save overwrites the first and one URL redirects to the wrong place. This is why a single random draw isn't enough. How often it happens depends on the collision space, the total number of distinct codes the scheme can produce: a 6-character base62 code gives 62^6 ≈ 56.8 billion possibilities, and CODE_LENGTH makes that a one-constant change if we outgrow it.
Injected randomness. Passing the random source into the generator as an argument (RandomSource = () => number) rather than calling global inside it. Production defaults to ; tests pass a known sequence. It is the chapter-6 seam idea applied to randomness, which is what lets work.
Math.randomMath.randomexpect(code).toBe("000000")Regenerate-on-collision loop. Draw a candidate, ask the store whether it's taken, and redraw until one is free. This is what turns "probably unique" into "definitely unique."
A generator that calls Math.random directly is random, and therefore untestable. You can't write expect(code).toBe("000000") against a value you can't predict ahead of time. The usual escape hatches are both bad: assert nothing specific (a weak test that passes even when the generator is broken), or mock the global Math.random (brittle, and the mock leaks into other tests if you forget to restore it).
Injecting the randomness source dissolves the tension. The generator takes its source as a parameter that defaults to Math.random:
typescriptexport type RandomSource = () => number;export const generateShortCode = (random: RandomSource = Math.random): string => {// ...};
In production we pass nothing, so it behaves exactly as you'd expect. In tests we pass a function that returns a scripted sequence of values, which makes the output an exact, asserted string. Same code, two randomness sources, zero flakiness, and not a single global touched.
Start from the red branch:
bashgit checkout 07-unique-short-codes-startnpm install
The branch ships two failing signals. First, a brand-new unit test for the generator that imports a module that doesn't exist yet:
typescript// __tests__/short-code.test.tsimport {ALPHABET,CODE_LENGTH,generateShortCode,generateUniqueShortCode,} from "../src/utils/short-code";import { UrlService } from "../src/services/url.service";const sequence = (values: number[]): (() => number) => {let index = 0;return () => values[index++ % values.length];};describe("generateShortCode", () => {it("produces a code of the configured length", () => {const code = generateShortCode(sequence([0]));expect(code).toHaveLength(CODE_LENGTH);});it("only uses characters from the base62 alphabet", () => {const code = generateShortCode(sequence([0.1, 0.4, 0.99, 0.5, 0.0, 0.73]));expect(code).toMatch(/^[0-9A-Za-z]{6}$/);for (const char of code) {expect(ALPHABET).toContain(char);}});it("is deterministic when the randomness source is injected", () => {expect(generateShortCode(sequence([0]))).toBe("000000");const almostOne = 0.999999;expect(generateShortCode(sequence([almostOne]))).toBe("zzzzzz");});it("maps each random value to the expected alphabet character", () => {const code = generateShortCode(sequence([10 / 62, 36 / 62, 10 / 62, 36 / 62, 10 / 62, 36 / 62]));expect(code).toBe("AaAaAa");});});describe("generateUniqueShortCode", () => {it("returns a fresh code when the store is empty", () => {const store = new UrlService();const code = generateUniqueShortCode(store, sequence([0]));expect(code).toBe("000000");});it("regenerates when the first candidate already exists in the store", () => {const store = new UrlService();store.save("000000", "https://dalabs.academy");const almostOne = 0.999999;const random = sequence([0,0,0,0,0,0,almostOne,almostOne,almostOne,almostOne,almostOne,almostOne,]);const code = generateUniqueShortCode(store, random);expect(code).toBe("zzzzzz");});});
This test is the whole specification, written before the code. Read it as a list of properties the generator must satisfy:
CODE_LENGTH (6) characters./^[0-9A-Za-z]{6}$/ and by asserting each char is in ALPHABET.0 give "000000"; six draws of 0.999999 give "zzzzzz". That's the determinism injection buys us.10/62 lands on index 10 ("A"), 36/62 on index 36 ("a"), so the interleaved sequence yields "AaAaAa"."000000", the first draw collides, so the function redraws and returns "zzzzzz".The sequence helper makes all of this possible. It closes over an index and returns the supplied values one per call. Feed it [0] and every call returns 0; feed it twelve values and you script the generator's behavior across two full codes. Because the generator pulls randomness through its parameter, a scripted sequence makes the output an exact, asserted value.
The second red signal is the route test, updated to expect a generated code instead of the hardcoded abc123:
typescript// __tests__/shorten.test.tsit("should return 201 with a generated short code and short URL", async () => {app = await buildApp({ logger: false, random: () => 0 });await app.ready();const url ="https://dalabs.academy/courses/test-driven-development-with-nodejs";const response = await app.inject({method: "POST",url: "/shorten",payload: { url },});expect(response.statusCode).toBe(201);expect(response.json()).toEqual({shortCode: "000000",url,shortUrl: "http://localhost:3000/000000",});});
The same injection seam reaches the HTTP layer. buildApp({ random: () => 0 }) threads a deterministic source all the way down to the route, so the test can assert the exact code "000000" instead of just "some string." A second test (not shown) builds the app with the default randomness and asserts shape only: the code matches /^[0-9A-Za-z]{6}$/ and flows unchanged into shortUrl. The split is deliberate. Pin the exact output where you control randomness, and assert the invariants where you don't.
Run it:
bashnpm test

Red, twice over. The new short-code.test.ts suite can't even start, because there's no ../src/utils/short-code module to import, and the route test fails its deep-equality check: it wants 000000, but the route still returns abc123. Both failures point at exactly the gap we're about to close.
There's a type-level failure too. Run npm run typecheck and TypeScript reports that random isn't a known property of BuildAppOptions yet, since the route test is already passing an option the app doesn't accept. We fix that in the wiring step.
Switch to the finish branch to see the implementation:
bashgit checkout 07-unique-short-codes-finish
The whole generator is one new file:
typescript// src/utils/short-code.tsimport { UrlStore } from "../services/url.service";export const ALPHABET ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";export const CODE_LENGTH = 6;export type RandomSource = () => number;export const generateShortCode = (random: RandomSource = Math.random): string => {let code = "";for (let i = 0; i < CODE_LENGTH; i++) {const index = Math.floor(random() * ALPHABET.length);code += ALPHABET[index];}return code;};export const generateUniqueShortCode = (store: UrlStore,random: RandomSource = Math.random): string => {let code = generateShortCode(random);while (store.findByCode(code) !== undefined) {code = generateShortCode(random);}return code;};
generateShortCode is a loop over CODE_LENGTH positions. For each one it calls random() to get a float in [0, 1), scales it by ALPHABET.length (62), and floors to an index in [0, 61]. random() === 0 maps to index 0 ("0"), and random() === 0.999999 maps to index 61 ("z"). That's why the test's six zeros produce "000000" and six near-ones produce "zzzzzz". The function is pure with respect to random: same sequence in, same code out, every time, with no global state, no hidden side effects, and nothing to mock.
generateUniqueShortCode is the uniqueness guarantee. It draws a candidate, then loops while store.findByCode(code) returns something other than undefined (meaning the code is already taken), drawing a fresh candidate each time. The first free code wins. With an empty store the first draw is returned immediately; with "000000" already present, the first draw collides, so it redraws and returns the next code the scripted sequence produces.
Notice what generateUniqueShortCode actually depends on: only UrlStore.findByCode, the interface we extracted in chapter 6. It has no idea whether the store is a Map or a database. When chapter 12 swaps the in-memory store for a Prisma-backed one, this collision logic doesn't change a line. Chapter 19 revisits collisions at the database level, where two concurrent inserts can race for the same code, a problem a single-process loop can't see.
The generator is correct in isolation, but the route still returns abc123. We replace that one line and thread the optional randomness source through the wiring, without changing the route's schema or response shape.
typescript// src/routes/shorten.tsimport { FastifyPluginAsync } from "fastify";import { UrlStore } from "../services/url.service";import { generateUniqueShortCode, RandomSource } from "../utils/short-code";interface ShortenRequestBody {url: string;}interface ShortenRouteOptions {urlStore: UrlStore;random?: RandomSource;}export const shortenRoute: FastifyPluginAsync<ShortenRouteOptions> = async (app,opts) => {const { urlStore, random } = opts;app.post<{ Body: ShortenRequestBody }>("/shorten", {schema: {description: "Create a shortened URL",tags: ["URLs"],body: {type: "object",required: ["url"],additionalProperties: false,properties: {url: { type: "string" },},},response: {201: {type: "object",required: ["shortCode", "url", "shortUrl"],properties: {shortCode: { type: "string" },url: { type: "string" },shortUrl: { type: "string" },},},},},handler: async (request, reply) => {const { url } = request.body;const shortCode = generateUniqueShortCode(urlStore, random);urlStore.save(shortCode, url);reply.code(201);return {shortCode,url,shortUrl: `http://localhost:3000/${shortCode}`,};},});};
Two changes from chapter 6. The hardcoded const shortCode = "abc123"; becomes const shortCode = generateUniqueShortCode(urlStore, random);, so the route now asks the generator for a fresh, store-checked code. And ShortenRouteOptions gains an optional random?: RandomSource, passed straight to the generator. Production omits it (the generator falls back to Math.random); the route test injects () => 0 to pin the output. The schema and the response body are byte-for-byte what they were, and only the value of shortCode is now generated rather than faked.
The same optional random flows one level up, through buildApp:
typescript// src/app.tsimport Fastify, { FastifyInstance } from "fastify";import swagger from "@fastify/swagger";import swaggerUi from "@fastify/swagger-ui";import { healthRoute } from "./routes/health";import { shortenRoute } from "./routes/shorten";import { UrlService } from "./services/url.service";import { RandomSource } from "./utils/short-code";interface BuildAppOptions {logger?: boolean;random?: RandomSource;}export const buildApp = async (opts: BuildAppOptions = {}): Promise<FastifyInstance> => {const app = Fastify({ logger: opts.logger ?? true });const urlStore = new UrlService();await app.register(swagger, {openapi: {info: {title: "URL Shortener API",description: "A URL shortener service built with Fastify and TDD",version: "1.0.0",},},});await app.register(swaggerUi, {routePrefix: "/documentation",});await app.register(healthRoute);await app.register(shortenRoute, { urlStore, random: opts.random });return app;};
BuildAppOptions now declares random?, and buildApp forwards it: register(shortenRoute, { urlStore, random: opts.random }). That one addition makes the type error from Step 1 go away, so buildApp({ random: () => 0 }) is now valid, and it gives the route test a clean, dependency-injected way to control the output without ever touching the global Math.random. The UrlService from chapter 6 is untouched.
Run the full suite:
bashnpm test

Green: four suites, twelve tests, covering the health check, the two shorten contract tests, the three UrlService tests from chapter 6, and the six new generator tests. npm run typecheck is clean too, now that random is a known option. The fake is gone, and every code the route returns is a real, unique, base62 string.
The route still happily shortens "not a url" or an empty string, because nothing checks the input. Next we validate the URL and reject malformed input before it ever reaches storage.