Search code examples
reactjsnext.jsvercelnext.js13supabase

What is the right way to do GET (all items or by a specific ID) in NextJS 13.4? (Response, NextAPIResponse, or NextResponse) using the new App Router?


What is the right way to do a GET (either getting all items or by a specific ID) in NextJS 13.4 in the new App Router?

The previous way of doing delete with using NextAPIRequest, NextAPIResponse, using if (req.method === 'GET') , pulling parameters from the URL via something like this const { id } = request.query;, and throwing error messages with NextAPIResponse seems to be outdated.

For clarity - please show how to grab data with both a GET "all" and a GET one that matches an UUID.


Solution

  • Here is an updated GET api in NextJS 13.4 using the new app routing with error messages included.

    For clarity of the example, I'll include a call to a supabase client; in your app, the API or client you're using to grab data can be different, but you can see the error messages and such in this example and you can modify to fit your situation.

    You need to create a specific folder + file like this: /app/api/tacos/route.js. The app router respects the folders and your code which does the specific handling of the HTTP Verbs should be in a file called route.js. I'll include the file name and route in the comments above the code block.

    // METHOD 1
    // FILE NAME /app/api/tacos/route.js
    // import { NextApiRequest, NextApiResponse } from 'next'; // this is was the OLD way pre-NextJS 13.4
    import { NextResponse } from 'next/server';
    import supabase from '../../supabase/client';
    import { useRouter } from 'next/navigation';
    
    export async function GET(request) {
      try {
        let { data, error } = await supabase.from('my_table').select('*');
         if (error) {
           return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
         }
         return NextResponse.json({ data });
      } catch (error) {
        return NextResponse.json({ error: 'Catch Error - Internal Server Error' }, { status: 500 });
      }
    }
    

    If instead you want to do a GET with a specific ID?

    You can do this one of two ways in the URL.

    In Method 2 - you can add a query string to the URL .

    // METHOD 2
    // FILE NAME /app/api/tacos/route.js
    import { NextResponse, NextRequest } from 'next/server';
    import supabase from '../../../supabase/client';
    
    export async function GET(request) {    
    // ! OLD WAY - no longer works
    // const { id } = request.query;
    
    // * THIS WORKS
    const searchParams = request.nextUrl.searchParams;
    const id = searchParams.get('id');
    
    try {
      let { data, error } = await supabase.from('my_table').select('*').eq('id', id);
      console.log('GET Method 2 supabase ~ data:', data);
      console.log('GET Method 2 supabase ~ error:', error);
    
      if (error) {
        console.log('GET Method 2 supabase ~ error:', error);
        return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
      }
    
      // * this also works
      // return NextResponse.json({ data }, { status: 200 });
      return NextResponse.json({ data });
    } catch (error) {
      console.log('GET Method 2 supabase -  Try/Catch ~ catch(error):', error);
      return NextResponse.json({ error: 'Try/Catch Error - Internal Server Error' }, { status: 500 });
      }
    }
    

    In Method 3, let's add this [slug] in the URL (so this requires putting the file route.js in a different place see the //comment a few lines down, and, to clarity for those who are unfamiliar, it requires you to create a folder with the name [id] under the folder tacos. The bracket notation is recognized by NextJS and when you call the api, you can replace that slug with a string like a UUID :

    // METHOD 3
    // FILE NAME /app/api/tacos/[id]/route.js
    import { NextResponse, NextRequest } from 'next/server';
    import supabase from '../../../supabase/client';
        
    export async function GET(request, { params }) {
      const id = params.id; // this is what will grab the string - use an UUID
      console.log(id);
    
    try {
      let { data, error } = await supabase.from('my_table').select('*').eq('id', id);
      console.log('GET Method 3 supabase ~ data:', data);
      console.log('GET Method 3 supabase ~ error:', error);
        
      if (error) {
        console.log('GET Method 3 supabase ~ error:', error);
        return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
      }  
      return NextResponse.json({ data });
      // * this also works
      // return NextResponse.json({ data }, { status: 200 });
    } catch (error) {
      console.log('GET Method 3 supabase -  Try/Catch ~ catch(error):', error);
      return NextResponse.json({ error: 'Try/Catch Error - Internal Server Error' }, { status: 500 });
      }
    }
    

    For clarity, in Typescript the function signatures would be something like, export async function GET(request: NextRequest) {

    Read more on route handlers here.

    ============== HERE IS HOW TO CALL THE API ===================

    For completeness, here are very simple functions I used in my client-side app to call this API. For simplicity, I hardcoded an id; in your app, you would want to pass an id as a parameter to the function.

    // METHOD 1
    const getAllData = async () => {
      try {
        const response = await fetch(`/api/saveCalculation`, {
            method: 'GET',
        });
    
        if (response.ok) {
            const data = await response.json();
            console.log('getAllData - Response OKAY - data', data);
            console.log('OKAY');
        } else {
            // Handle the error
            console.log('getAllData - Response NOT OKAY');
        }
      } catch (error) {
        console.error('getAllData - Try/Catch - Error', error);
      }
    };
    
    
    // METHOD 2
    const getSpecificID = async () => {
    const id = 'addYour-UUID-here-2323-232323232323';
    
      try {
      const response = await fetch(`/api/saveCalculation?id=${id}`, {
        method: 'GET',
      });
    
      if (response.ok) {
          const data = await response.json();
          console.log('Response OKAY - responseData', data);
          console.log('OKAY');
        } else {
        // Handle the error
        console.log('Response NOT OKAY');
        const data = await response.json();
        console.log('getSpecificID - Response not OK', data);
      }
      } catch (error) {
      console.error('Try/Catch - Error', error);
      const data = await response.json();
      console.log('getSpecificID - Response not OK', data);
      }
    };
    
    
    
    // METHOD 3
    const getSpecificIDByUrl = async () => {
    const id = 'addYour-UUID-here-2323-232323232323';
    
      try {
      const response = await fetch(`/api/saveCalculation/${id}`, {
        method: 'GET',
      });
    
      if (response.ok) {
        const data = await response.json();
        console.log('Response OKAY - data', data);
        console.log('OKAY');
      } else {
        // Handle the error
        console.log('Response NOT OKAY');
        const data = await response.json();
        console.log('getSpecificIDByUrl - Response not OK', data);
      }
      } catch (error) {
      console.error('Try/Catch - Error', error);
      const data = await response.json();
      console.log('getSpecificIDByUrl - Response not OK', data);
      }
    };