30.7 Generating OpenAPI Specs from TypeScript Route Definitions

Right, so you’ve built a beautiful, type-safe API with TypeScript, Express, and Fastify. It feels solid. You’re not sending strings that should be integers or booleans that should be dates. But now someone—a frontend team, a client, your future self who forgot everything—asks for the API documentation. You’re not going to hand-write an OpenAPI spec, are you? That would be like building a perfect, self-documenting castle and then painting the blueprints by hand on the outside wall. We automate this.

30.6 Validation Libraries: Zod and TypeBox for Request Validation

Right, let’s talk about keeping the barbarians at the gate. You’ve got an Express or Fastify endpoint, and you’re trusting the internet—a collection of cats, bots, and malicious actors—to send you well-formed, perfectly typed data. Hilarious, right? We both know any is a lie we tell ourselves to feel safe at night. The request body is a terrifying unknown, and it’s our job to turn it into something we can actually use without blowing up the entire application. That’s where runtime validation comes in, and Zod and TypeBox are your two best friends for this particular trench warfare.

30.5 Fastify Plugins and the Typed Plugin Pattern

Alright, let’s talk about Fastify plugins. This is where Fastify truly flexes its architectural muscles and leaves other frameworks looking a bit… basic. The plugin system isn’t just a way to add features; it’s the fundamental, first-class way you build anything in Fastify. It’s how you encapsulate functionality, manage dependencies, and—crucially for us—how we get TypeScript to understand our entire application’s structure. Think of a Fastify plugin as a neatly wrapped package containing routes, decorators, and hooks. The magic is that these packages can be developed, tested, and reasoned about in isolation before being seamlessly integrated into your main application. It’s the opposite of the “just attach stuff to the app object and pray” pattern you might be used to.

30.4 Fastify with TypeScript: Schema-Based Request Typing

Alright, let’s talk about the part of Fastify that makes TypeScript developers do a little happy dance: schema-based request typing. This is where Fastify flexes hard on other frameworks. While Express has you writing any or awkward req as RequestWithBody casts, Fastify bakes type safety directly into your route’s DNA. It’s not a bolted-on afterthought; it’s the foundation. The magic lies in Fastify’s use of JSON Schema. You define the shape and validation rules for your request’s body, querystring, params, and even headers using a schema. Fastify then does two brilliant things for you: it validates incoming requests against that schema (bye-bye, a lot of your manual validation logic!) and, crucially, it generates strong TypeScript types from that schema. You write the rules, and Fastify hands you the types. It’s like getting the blueprint and the finished product at the same time.

30.3 Typed Middleware: RequestHandler and ErrorRequestHandler

Alright, let’s talk middleware. This is where the rubber meets the road in your server setup. Middleware functions are the bouncers, the paperwork processors, and the emergency crews of your application. They have access to the request object (req), the response object (res), and that all-important next function in the application’s request-response cycle. In vanilla JavaScript, you’d just slap a function in there and hope for the best. But we’re better than that. We have types. TypeScript’s power here is that it lets you define exactly what each middleware expects and what it’s allowed to do, turning runtime guesswork into compile-time certainty.

30.2 Extending express.Request with Custom Properties

Right, so you’re building an Express app and you’ve hit the point where you need to store some custom data on the request object. Maybe you’ve just authenticated a user and you want to slap their entire profile object onto req.user. Your first instinct in TypeScript is probably to just reach out and extend the Request interface. It’s a good instinct, but if you do it naively, you’ll be smacking headfirst into a wall of red squiggles. Let’s break down why that happens and how to do it properly.

30.1 Express with TypeScript: Typed Request and Response

Right, let’s get you set up with Express and TypeScript without losing your mind. The first thing you’ll realize is that Express, bless its heart, was not built with type safety in mind. Out of the box, its Request and Response objects are about as typed as a bowl of soup. Your job is to add the cutlery. The Vanilla (and Painfully Untyped) Problem If you just start writing Express handlers with TypeScript, you’re in for a world of any. Look at this sad, lonely handler:

— joke —

...