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

Three main concepts drive this chapter. The codes themselves are base62. This means they are built from a 62-character alphabet (0-9, then A-Z, then a-z). Because there are no symbols or punctuation, a base62 code drops cleanly into a link with nothing extra to URL-encode.
A collision happens when two different URLs get assigned the exact same short code. If this occurs, the second save overwrites the first, and one URL will redirect to the wrong place. This is why a single random draw is rarely enough. How often collisions happen depends on the total number of distinct codes the system can produce. A 6-character base62 code gives 62^6 ≈ 56.8 billion possibilities. We will use a CODE_LENGTH constant so we can easily increase that size later if we outgrow it.
Injected randomness means passing the random source into the generator as an argument (RandomSource = () => number) instead of calling the global Math.random directly inside the function. In production, the app defaults to Math.random. In tests, we pass a known sequence of numbers. This is the same seam idea from chapter 6 applied to randomness, and it lets us write exact assertions like expect(code).toBe("000000").
A regenerate-on-collision loop draws a candidate code, asks the store if it is taken, and redraws until it finds a free one. This process turns a "probably unique" code into a "definitely unique" one.
A generator that calls Math.random directly is completely random, which makes it hard to test. You cannot write expect(code).toBe("000000") against a value you cannot predict. The common workarounds are unhelpful. You might assert nothing specific, which creates a weak test that passes even when the generator is broken. Or, you might mock the global Math.random, which is brittle and can leak into other tests if you forget to restore it.
Injecting the randomness source solves this problem. 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 normally. In tests, we pass a function that returns a scripted sequence of values. This makes the output an exact, predictable string. We get the same code, two different randomness sources, zero flakiness, and no global variables touched.
Start from the red branch:
bashgit checkout 07-unique-short-codes-startnpm install
The branch ships two failing signals. First is a brand-new unit test for the generator. It imports a module that does not 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 acts as the whole specification, written before the code itself. You can read it as a list of properties the generator must satisfy:
CODE_LENGTH (6) characters./^[0-9A-Za-z]{6}$/ and by asserting each character is in ALPHABET.0 give "000000". Six draws of 0.999999 give "zzzzzz".10/62 lands on index 10 ("A"), and 36/62 lands on index 36 ("a"). The interleaved sequence yields "AaAaAa"."000000", the first draw collides. The function then redraws and returns "zzzzzz".The sequence helper makes this testing 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 guarantees an exact output.
The second red signal is the route test. It is 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. Calling buildApp({ random: () => 0 }) threads a deterministic source all the way down to the route. This lets the test assert the exact code "000000" instead of just checking for a generic string. A second test (not shown) builds the app with the default randomness and asserts the shape only. It checks that the code matches /^[0-9A-Za-z]{6}$/ and flows unchanged into shortUrl. This split is deliberate. We pin the exact output where we control the randomness, and we assert the general shape where we do not.
Run it:
bashnpm test

The tests fail twice over. The new short-code.test.ts suite cannot even start because there is no ../src/utils/short-code module to import. The route test fails its deep-equality check because it expects 000000, but the route still returns abc123. Both failures point at the gap we are about to close.
There is also a type-level failure. If you run npm run typecheck, TypeScript reports that random is not a known property of BuildAppOptions. The route test is passing an option the app does not accept yet. We will 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 loops over CODE_LENGTH positions. For each position, it calls random() to get a decimal number between 0 and 1. It scales that number by ALPHABET.length (62) and rounds down to an index between 0 and 61. A random value of 0 maps to index 0 ("0"), and a value of 0.999999 maps to index 61 ("z"). This is why the test's six zeros produce "000000" and six near-ones produce "zzzzzz". The function is pure with respect to random. The same sequence in gives the same code out, with no global state and nothing to mock.
generateUniqueShortCode provides the uniqueness guarantee. It draws a candidate code, then loops as long as store.findByCode(code) finds an existing match. It draws a fresh candidate each time until it finds a free code. With an empty store, the first draw is returned immediately. If "000000" is already present, the first draw collides, so the function redraws and returns the next code from the sequence.
Notice what generateUniqueShortCode depends on. It only relies on UrlStore.findByCode, the interface we extracted in chapter 6. It has no idea whether the store is a simple Map or a real database. When chapter 12 swaps the in-memory store for a Prisma-backed database, this collision logic will not change at all. Later, chapter 19 will revisit collisions at the database level, where two concurrent inserts can race for the same code, a problem this single-process loop cannot see.
The generator works in isolation, but the route still returns abc123. We need to replace that hardcoded line and thread the optional randomness source through the application wiring. We will do this 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}`,};},});};
There are two main changes from chapter 6. First, the hardcoded const shortCode = "abc123"; becomes const shortCode = generateUniqueShortCode(urlStore, random);. The route now asks the generator for a fresh, store-checked code. Second, ShortenRouteOptions gains an optional random?: RandomSource property, which is passed straight to the generator. Production omits this option, so the generator falls back to Math.random. The route test injects () => 0 to pin the output. The schema and the response body remain exactly the same. Only the value of shortCode is generated rather than faked.
The same optional random parameter 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 using register(shortenRoute, { urlStore, random: opts.random }). This single addition makes the type error from Step 1 go away. Calling buildApp({ random: () => 0 }) is now valid. It gives the route test a clean, dependency-injected way to control the output without touching the global Math.random. The UrlService from chapter 6 remains untouched.
Run the full suite:
bashnpm test

The tests pass. We have four suites and twelve tests covering the health check, the two shorten contract tests, the three UrlService tests from chapter 6, and the six new generator tests. Running npm run typecheck is also clean now that random is a known option. The fake value 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 will validate the URL and reject malformed input before it ever reaches storage.