What is the process for incorporating a custom type into Next.js's NextApiRequest object?

I have implemented a middleware to verify JWT tokens for API requests in Next.js. The middleware is written in TypeScript, but I encountered a type error.

Below is my code snippet:

import { verifyJwtToken } from "../utils/verifyJwtToken.js";
import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import cookie from "cookie"

const authMiddleware = (handler: NextApiHandler) => async (req: NextApiRequest, res: NextApiResponse) => {
  try {
    
 
    const cookies = cookie.parse(req.headers.cookie || '')
    const token = cookies.token
    const verifiedToken = await verifyJwtToken(token)

    if (!verifiedToken) {
      throw new Error('You have no access to do it.')
    }
    
    const userId = Number(verifiedToken.id)

    // Call the API route handler with the updated request object
    return handler({ ...req, userId }, res)
  } catch (err) {
    console.error(err)
    res.status(401).json({ message: 'You have no access to do it.' })
  }
}

export default authMiddleware;

The type error I encountered is as follows:

Argument of type '{ userId: number; query: Partial<{ [key: string]: string | string[]; }>; cookies: Partial<{ [key: string]: string; }>; body: any; env: Env; preview?: boolean | undefined; ... 35 more ...; eventNames(): (string | symbol)[]; }' is not assignable to parameter of type 'NextApiRequest'.

Object literal may only specify known properties, and 'userId' does not exist in type 'NextApiRequest'.ts(2345)

To resolve this issue, I created a custom interface that extends NextApiRequest and includes the userId property. Here is an example:

import { NextApiRequest } from 'next'

interface CustomNextApiRequest extends NextApiRequest {
  userId: number
}

export default CustomNextApiRequest;

Subsequently, I attempted to utilize this custom interface as the type for the req parameter in the middleware function, like so:

import CustomNextApiRequest from './CustomNextApiRequest';

const authMiddleware = (handler: NextApiHandler) => async (req: CustomNextApiRequest, res: NextApiResponse) => {
  // ...
}

However, this approach did not work. It's important to note that the code is functional, but I am aiming to rectify the type error.

Additionally, here is how I applied the authMiddleware:

async function addCommentHandler(req: NextApiRequest, res: NextApiResponse) {
  // Implementation logic goes here...
}
export default authMiddleware(addCommentHandler);

Answer №1

Your CustomNextApiRequest declaration appears to be correct. However, there seems to be an issue in how your middlewares are connected. I recommend creating a CustomNextApiHandler as shown below (feel free to adjust the return type):

interface CustomNextApiRequest extends NextApiRequest {
  userId: number;
}
export type CustomNextApiHandler = (req: CustomNextApiRequest, res: NextApiResponse) => void;

Your addCommentHandler should utilize the defined CustomNextApiHandler type:

export const addCommentHandler: CustomNextApiHandler = (req, res) => {};

Lastly, update your authMiddleware function to include the following changes (observe the additional comment):

const authMiddleware =
  (handler: CustomNextApiHandler) => async (req: CustomNextApiRequest, res: NextApiResponse) => {
    try {
      const cookies = cookie.parse(req.headers.cookie || "");
      const token = cookies.token;
      const verifiedToken = await verifyJwtToken(token);

      if (!verifiedToken) {
        throw new Error("You do not have permission to perform this action.");
      }
      const userId = Number(verifiedToken.id);
      // Assigning userId directly instead of using destructuring
      req.userId = userId;
      // Execute the API route handler with the updated request object
      return handler(req, res);
    } catch (err) {
      console.error(err);
      res.status(401).json({ message: "You do not have permission to perform this action." });
    }
  };

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps to incorporate / insert Angular directive in an application

In my app, the main.js file is located in the root folder. -app |_ routes.js |_ main.js -components |_directives |_abc-directive.js I am trying to figure out how to define a directive that can be accessed from a different folder. This is what I at ...

Error encountered in Azure Pipelines build task: Failure due to requirement for initialization

When I directly invoke index.js using node, everything works fine. However, when running the Mocha tests, the task fails with a "Must initialize" error message. This is how my tasks index.ts code looks like: import * as path from "path"; import tl = requ ...

Executing Code Within Promises and Utilizing return Statements

When using promises, do I need to explicitly return the resolve and reject methods? The code runs smoothly for single condition statements, but what happens if there are multiple conditions - will reject and resolve automatically end or do we need to use ...

What is the best way to transfer the search query to a table filter when working with multiple JavaScript files?

I am struggling with passing the search query from my search file to my table file. The data for my datagrid table is retrieved from a database using an API call, and the table code is in one file while the search functionality code is in another file. I h ...

Next.js app encounters a BSON error when using TypeORM

Currently, I am in the process of integrating TypeORM into my Next.js application. Despite utilizing the mysql2 driver and configuring 5 data sources, I am encountering a persistent BSON error: ./node_modules/typeorm/browser/driver/mongodb/bson.typings.js ...

Combining Two DIVS Side by Side

Hey there, I am working on a timeline using two divs within a table cell. My goal is to have these divs overlap instead of appearing one below the other. The position attribute for all the DIVs inside the cell must remain unchanged due to the drag/drop fu ...

Troubleshooting the Hide/Show feature in React Native

As a newcomer to React Native development, I am attempting something simple. Within a React Class extending Component, I have 4 components <TouchableOpacity>. In the render function, my goal is to hide three of these components while pressing on one ...

Bidirectional data binding in Angular 2 allows for communication between parent components and directives

Update: Experimenting with Angular2 Beta, I am working on incorporating an "editor" component template that includes a directive wrapping the Ace editor. In this scenario, the "editor" component acts as the parent of the Ace wrapper directive, and my goal ...

What is the process for converting a string literal into raw JSON and then storing it?

When trying to edit object values using a text input element and JSON.stringify(txt, null, 2), everything seems fine initially. However, after submitting the input, I end up with unwanted characters like "/n" and "\" within the string literal. Despite ...

Unable to retrieve the data-id from the ajax response for extraction and transfer to the modal

I am encountering an issue when trying to retrieve the data-id from an AJAX response within a href tag. The response always returns as undefined. $("#loader_ekpresi").show(); $.ajax({ url:"<?php echo site_url() ?>Home/get_ekspresi", type:& ...

Begin counting starting from 1 all the way up to 24, then feel free

I've developed a counter that increments from 0 to 24, and once it reaches 24: setInterval(function(){DayAndNight()}, 1000); var iState = 12; function DayAndNight() { //console.log('test'); switch(iState) ...

The chatbot text input feature is malfunctioning and failing to display the entered text in the chatbox

Hi there! I'm in the process of creating a chatbot using a basic input text box and button in HTML, with a php start function. Unfortunately, when I enter text into the textbox, nothing is showing up on the screen and the button doesn't seem to b ...

Common Errors in Angular 2 due to TSLint

I am encountering multiple errors in my code. I am using Angular 2 with TSLint: constructor(http: Http) { this.http = http; --> let currentUser = JSON.parse(localStorage.getItem("currentUser")); this.token = currentUser && currentUser.t ...

React 18 update causes malfunctioning of react-switch-selector component

I'm facing an issue where the component is not rendering. I attempted to start a new project but it still didn't work. Is there a solution to fix this problem or should I just wait for an update from the original repository? Encountered Error: ...

What is the process for integrating the Bootstrap JS library into a Next.js project?

My upcoming project involves server-side rendering with Next.js, and I plan to incorporate Bootstrap into it. After some research, I decided to import Bootstrap into my root layout like this: import { Inter } from "next/font/google"; import " ...

What is the method employed by Node.js to manage relative paths?

I am facing an issue with how Node.js handles paths. Despite checking the documentation, I couldn't find the solution to my problem. Basically, I have a file that contains a relative path pointing to another file (specifically a PNG image). Dependin ...

Storing a collection of items in an array using jQuery

Looking to organize list items from multiple lists of the same class into an array. For example: <ul class="myList"> <li>item 1</li> <li>item 2</li> </ul> <ul class="myList"> <li>i ...

``Unresolved issue: Sending emails using Sendgrid and Firebase not working in production through Netlify

For a simple contact form, I am utilizing Nuxt, Sendgrid, and Firebase. Netlify is being used for hosting the project. The contact form works perfectly fine locally and sends emails without any issues. However, once I push the project to Netlify, the email ...

Get notified with ng2-smart-table updates when editing

I am trying to control the edit feature of my ng2-smart-table, but the code I have isn't working. Am I missing something? HTML <ng2-smart-table [settings]="settings" [source]="source" (edit)="onEdit($event)"></ng2-smart-table> Component ...

The collaboration between Redux's combineReducers and the power of TypeScript

I'm facing a challenge with using react-intl-redux and redux-form in my react app, specifically when working with combineReducers. Despite trying multiple approaches, I haven't been able to resolve the issue. react-intl-redux import { combineRe ...