How to add custom types to Nuxt3 server API context

Nuxt3 is a Hybrid (Full-Stack) Vue 3 framework. It allows you to create file-based API routes on the server-side which uses Nitro and H3 under the hood. Here's a trick to help with TypeScript types on your server context.

Getting started with Nuxt 3

First we actually need an example, to start a Nuxt 3 project simply do:

npx nuxi init my-awesome-project

This will generate a new nuxt app for you, once it's cloned, run:

cd my-awesome-project && yarn install && npx nuxi prepare

This will install all your dependencies and npx nuxi prepare will generate the base types of your project.

Creating an API route

server/api/todos.get.ts

export default defineEventHandler(async (event) => ['todo1', 'todo2'])

Create the file above, you don't need to import anything because defineEventHandler is part of Nuxt3's Auto Imports. The event has a property called context and it's native type is Record<string, any>. So let's add a fake 'Auth' module in a global middleware. First, let us protect our route:

export default defineEventHandler(async (event) => {
  const user = event.context.auth; // 'auth' will not be typed, we want to see what's available on auth.

  if (user.validate(/* Does this accept params?? */)) {
    return ['todo1', 'todo2'];
  }

  return []; // Not authed buddyyy.
})

The code above requires us to create a middleware to update the event context a little:

server/middleware/auth.ts

export interface User {
  id: string;
  email: string;
  validate: (forceRefresh?: boolean ) => boolean; // oh, it has a param 🤔
}

export default defineEventHandler((event) => {
  const user: User = {
    id: '1234',
    email: '[email protected]',
    validate(forceRefresh) {
      // Some logic here using forceRefresh etc.
      return true;
    },
  };

  event.context.auth = user;
});

Above we do clearly define the type of User, but in server/api/todos.get.ts the type will be 'any' on the context, leaving us blind. So here's how we can work around that:

server/context.d.ts

import type {User} from './middleware/auth';
import type {IncomingMessage, H3Event} from 'h3';

declare module 'h3' {
  interface CompatibilityEvent extends IncomingMessage, H3Event {
    context: {
      [key: string]: any; // or 'unknown' 🤔?
      auth?: User;
    };
  }
}

Now we have full typing of our context on the Nuxt 3 API routes. As you add stuff to context just keep updating the types in this file:




Thank you for reading and I hope this helped you out. If you want to Support Me feel free 😀, other ways for you to follow me is on Twitter or on Youtube. Happy hacking!