Retrieve a user by their _id, remove a user using their _id, and modify a user based on their _id using Next.js 14, utilizing Typescript

I'm currently troubleshooting three request methods that are not functioning properly: GET, UPDATE, and DELETE for a user by _id.

When I try to run these requests in the browser or postman, I receive a "no page found" error in the API call.

The route for calling my API is http://localhost:3000/api/users, which successfully retrieves all users. However, when I attempt to access a specific user using the URL http://localhost:3000/api/users/{_id}, replacing {_id} with the actual user ID, I encounter a "no page found" issue.

Below is the code for the 3 requests:

// Function to get user by _id
export async function getUserById(req: NextApiRequest, res: NextApiResponse) {
  try {
    console.log('Route accessed:', req.url); // Logging the accessed route

    const { id } = req.query; // Retrieving the _id parameter from the request query

    // Fetching user by _id from UserModel
    const user = await connectAndDisconnect(() => UserModel.findById(id as string));

    if (!user) {
      console.log('User not found:', id);
      return res.status(404).json({ error: 'User not found' });
    }

    // Returning the fetched user
    return res.status(200).json(user);
  } 
  catch (error) {
    console.error('Error fetching user by ID:', req.query.id, error);
    return res.status(500).json({ error: 'Internal Server Error' });
  }
}

// Function to update user by _id
export async function updateUserById(request: NextRequest) {
  const userId = request.nextUrl.searchParams.get('_id');
  const { body } = request;

  if (!userId) {
    return new NextResponse('Invalid user ID', { status: 400 });
  }

  const updatedUser = await asyncHandler(
    () =>
      connectAndDisconnect(() =>
        UserModel.findByIdAndUpdate(userId, body as Partial<IUser>, { new: true })
      ),
    'Error updating user by ID'
  );

  if (!updatedUser) {
    return new NextResponse('User not found', { status: 404 });
  }

  const jsonUpdatedUser = JSON.stringify(updatedUser);

  return new NextResponse(jsonUpdatedUser, {
    headers: { 'Content-Type': 'application/json' },
  });
}

// Function to delete user by _id
export async function deleteUserById(request: NextRequest) {
  const userId = request.nextUrl.searchParams.get('_id');

  if (!userId) {
    return new NextResponse('Invalid user ID', { status: 400 });
  }

  const deletedUser = await asyncHandler(
    () => connectAndDisconnect(() => UserModel.findByIdAndDelete(userId)),
    'Error deleting user by ID'
  );

  if (!deletedUser) {
    return new NextResponse('User not found', { status: 404 });
  }

  const jsonDeletedUser = JSON.stringify(deletedUser);

  return new NextResponse(jsonDeletedUser, {
    headers: { 'Content-Type': 'application/json' },
  });
}

Here is the content of the route.ts file:

// api/users.ts
import { NextRequest, NextResponse } from 'next/server';
import { createUser, getAllUsers, getUserById, updateUserById, deleteUserById } from 
'@/app/controllers/user';
import handleRequest from '@/app/middleware/handlerequest';

export async function GET(request: NextRequest) {
  return handleRequest(request, {
    '/api/users': getAllUsers,
    '/api/users/:id': getUserById,
  });
}

export async function POST(request: NextRequest) {
  return handleRequest(request, {
    '/api/users': createUser,
  });
}

 export async function PUT(request: NextRequest) {
   return handleRequest(request, {
     '/api/users/:id': updateUserById,
   });
 }

 export async function DELETE(request: NextRequest) {
   return handleRequest(request, {
     '/api/users/:id': deleteUserById,
   });
 }

Answer №1

I am not entirely convinced by the way this project is structured. It seems to follow a similar pattern as the Pages router approach in api/users.ts, but instead of exporting a unique handler, it exports methods like GET|POST|etc. Additionally, the dynamic part [[id]] appears to be missing.

In the App directory, it might be more appropriate to have app/users/route.ts and app/users/[id]/route.ts, where you can expose methods such as GET|POST|etc. However, implementing this change could potentially disrupt your middleware, as it was not initially designed for this type of usage.

If you are considering Next.js 14, you may want to explore using route handlers (refer to this documentation).

// app/products/api/users/[id]/route.ts

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const id = searchParams.get('id')
  const user = await getUserById(id)
 
  return Response.json({ user })
}

The structure aligns closely with the Pages router method (the traditional way), where you need to export a single default function and handle methods manually. It is crucial to ensure that the file name includes the optional [[id]] dynamic segment.

(Refer to API routes documentation for further details.)

// pages/api/users/[[id]].ts

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'GET') {
    const { id } = req.query
    if (id) {
      const user = await getUserById(id)
      res.status(200).json({ user })
    } else {
      // Get users list
    }
  } else {
    // Handle any other HTTP method
  }
}

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

Converting hexadecimal to binary using Javascript or Typescript before writing a file on an Android or iOS device

Hey everyone! I'm facing a puzzling issue and I can't seem to figure out why it's happening. I need to download a file that is stored in hex format, so I have to first read it as hex, convert it to binary, and then write it onto an Android/ ...

RXJS expand keeps on recursing indefinitely

After successfully uploading a file to Firebase, I implemented a recursive function to listen for GCP trigger logs. Everything seems to be working well, but I'm facing an issue where the recursive expand function never exits. Despite checking the val ...

Is it possible to use jQuery to set a value for a form control within an Angular component?

I'm currently working on an Angular 5 UI project. In one of my component templates, I have a text area where I'm attempting to set a value from the component.ts file using jQuery. However, for some reason, it's not working. Any suggestions o ...

Using Vue in conjunction with TypeScript and CSS modules

I am facing an issue with my SFC (single file vue component) that utilizes TypeScript, render functions, and CSS modules. <script lang="ts"> import Vue from 'vue'; export default Vue.extend({ props: { mode: { type: String, ...

Exploring ways to interact with an API using arrays through interfaces in Angular CLI

I am currently utilizing Angular 7 and I have a REST API that provides the following data: {"Plate":"MIN123","Certifications":[{"File":"KIO","Date":"12-02-2018","Number":1},{"File":"KIO","Date":"12-02-2018","Number":1},{"File":"preventive","StartDate":"06 ...

A unique column in the Foundry system that utilizes function-backed technology to calculate the monthly usage of engines over a

In my dataset of ‘Engine Hours’, I have the following information: Engine# Date Recorded Hours ABC123 Jan 21, 2024 9,171 ABC123 Dec 13, 2023 9,009 ABC123 Oct 6, 2023 8,936 XYZ456 Jan 8, 2024 5,543 XYZ456 Nov 1, 2023 4,998 XYZ456 Oct 1 ...

Encountering a "No session persistence storage option available" error while working on a Next.js 12 + Supabase project

I'm currently working on a project that involves Supabase and Next.js version 12.3.4. I managed to set up Google sign-in following the steps outlined in this helpful tutorial: Supabase Login with Google. However, every time I run the project, Terminal ...

Utilizing several data sources within a single mat-table

Hello, I require assistance with a task. I am trying to display multiple mat-tables with different data sources in my component.ts file Groups(){ this.apiSvc.Cards().subscribe((rsp: any) => { this.groups = rsp; this ...

What is the best way to transfer image files into a specific folder?

I am currently in the process of developing a ReactJS web application. My goal is to upload images to a specific folder and then store the file name in the database for future use. Everything seems to be working smoothly up to this point, but I am facing ...

Quick + Vue Router - Lazy Loading Modules

For my personal project, I am using Vite alongside Vue 3 and have integrated vue-router@4 for managing routes. Since all of my modules share the same set of routes, I created a helper function: import { RouteRecordRaw } from 'vue-router' import p ...

Quick tutorial on how to effortlessly add images or files to your Next.js app hosted on Vercel

When I transfer images from my local host, everything functions perfectly. However, once I deploy the Next.js app to Vercel and attempt to upload files or images through Cloudinary, it fails to work. What steps can I take to troubleshoot this issue? I am ...

Issue with Angular 2: Service not reflecting updated variable

I am currently working on creating an API service and trying to assign the data to a variable. However, I am facing an issue where the variable is not updating and ends up being undefined when I try to log it after calling the API service. import {Compone ...

Find the duplicated entries within a sub document array using a MongoDB query

In this scenario, the goal is to identify duplicate records in the sub-document based on certain conditions and output the results as outlined below. Dataset [{ _id: "objectId", name: "product_a", array: [{ _id: "objectId", st ...

The element 'loginToken' is not found within the type '{ loginToken: string; } | { error: Error; } | { username: string; password: string; }'

I'm currently working on creating a reducer using Typescript and Redux, but I keep running into this error: Property 'loginToken' is not recognized in type '{ loginToken: string; } | { error: Error; } | { username: string; password: str ...

Exploring the world of mocking tests using Jest and inputs

Is there a way to create a jest test specifically for this function? const input = require('prompt-sync')(); export function choices(): void { const choice = input("Choose a letter"); if (choice === "a") { con ...

Is it possible to continuously re-render a React Functional Component with Axios and useState/useEffect?

Seeking assistance with creating a React Functional Component using Typescript to fetch data from an API and pass it to another component. However, encountering the error message "Error: Too many re-renders. React limits the number of renders to prevent an ...

How can variables from state be imported into a TypeScript file?

Utilizing vue.js along with vuetify, I have a boolean value stored in state via Vuex defined in src/store/index.ts (named darkMode). This value is used within one of my view components inside a .vue file. However, I now wish to access the same variable in ...

The expiration period set in expireAfterSeconds doesn't seem to be functioning as expected in the time-to-live (ttl) configuration. Rows are

Can you please take a look at my code and provide some feedback? The issue I am facing is that the record is getting deleted without specifying the number of seconds. I have tried changing from createIndex to ensureIndex but it's still not working as ...

The data type 'void | Observable<any>' cannot be assigned to the type 'ObservableInput<any>'. Specifically, the type 'void' cannot be assigned to 'ObservableInput<any>'

I encountered an error in my visual studio code: Argument of type '(query: string) => void | Observable' is not assignable to parameter of type '(value: string, index: number) => ObservableInput'. Type 'void | Observable& ...

Linking Google Form Data to a MongoDB Database

Looking to integrate Google form with mongodb for data collection. Need help setting it up using NodeJs. Any advice on how to approach this? ...