Need help in fetching videos of users

I am using next js framework for my project. i want to display videos of a specific user on my web page. Unfortunately there are bugs in my code and would appreciate help in resolving those bugs.

My folder structure for this is as follows
src/app/twitch and in twitch folder i have page.tsx

I want to fetch data on server side but i am getting error on these lines

“const tokenResponse = await axios.post(” = Request failed with status code 400;
const videos: TwitchVideoResponse = await getTwitchVideos(“641972806”); = same error

How can i fix? I NEED HELP! i tried everything even chatgpt

This is my code:

import axios from "axios";

export interface TwitchVideoResponse {
  data: TwitchVideo[];
}

export interface TwitchVideo {
  id: string;
  user_name: string;
  title: string;
  url: string;
  thumbnail_url: string;
  type?: string;
  duration?: string;
}

const getTwitchVideos = async (user_id: string) => {
  const client_id = process.env.TWITCH_CLIENT_ID;
  const client_secret = process.env.TWITCH_CLIENT_SECRET;
  const appURL = `https://api.twitch.tv/helix/videos?user_id=${user_id}`;

  const tokenResponse = await axios.post(
    `https://id.twitch.tv/oauth2/token`,
    null,
    {
      params: {
        client_id: client_id,
        client_secret: client_secret,
        grant_type: "client_credentials",
      },
    }
  );

  const accessToken = tokenResponse.data.access_token;
  console.log("Access Token:", accessToken);

  const result = await axios.get(appURL, {
    headers: {
      "Client-ID": client_id,
      Authorization: `Bearer ${accessToken}`,
    },
  });

  console.log("Result:", result.data);

  if (!result.data || !result.data.data || result.data.data.length === 0) {
    throw new Error("No videos found for the given user ID");
  }

  return result.data;
};

const TwitchPage = async () => {
  const videos: TwitchVideoResponse = await getTwitchVideos("641972806");

  return (
    <div>
      <h1>Twitch Videos</h1>
      <ul>
        {videos && videos.data.map((video: TwitchVideo) => <li key={video.id}>{video.title}</li>)}
      </ul>
    </div>
  );
};

export default TwitchPage;

What is the body message of the response?

The HTTP code is half the information

so heres the updated version:
i created a new folder under app directory
app/api/twitch and in twitch folder created a route.ts

and this is my code for now

export async function GET(req: NextApiRequest, res: Response) {
  const { user_id } = req.query;
  console.log("User ID:", user_id);    


  const client_id = process.env.TWITCH_CLIENT_ID;
  const client_secret = process.env.TWITCH_CLIENT_SECRET;
  const appURL = `https://api.twitch.tv/helix/videos?user_id=${user_id}`;

  if (!client_id || !client_secret) {
    console.error("Twitch client ID or client secret not found");
    throw new Error("Twitch client ID or client secret not found");
  }

  const tokenParams = new URLSearchParams({
    client_id: client_id,
    client_secret: client_secret,
    grant_type: "client_credentials",
  });

  // Fetching access token

  const tokenResponse = await fetch(`https://id.twitch.tv/oauth2/token`, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: tokenParams,
  });

  if (!tokenResponse.ok) {
    console.error("Failed to fetch access token:", tokenResponse.statusText);
    throw new Error(
      `Failed to fetch access token: ${tokenResponse.statusText}`
    );
  }

  const tokenData = await tokenResponse.json(); 

  const accessToken = tokenData.access_token;

  // Fetching Twitch videos

  const videoResponse = await fetch(appURL, {
    headers: {
      "Client-ID": client_id,
      Authorization: `Bearer ${accessToken}`,
    },
  });

  if (!videoResponse.ok) {
    console.error("Failed to fetch videos:", videoResponse.statusText);
    throw new Error(`Failed to fetch videos: ${videoResponse.statusText}`);
  }

  const result = await videoResponse.json();
  console.log("Result:", result);

  if (!result.data || result.data.length === 0) {
    console.error("No videos found for the given user ID");
    throw new Error("No videos found for the given user ID");
  }

  // res.status(200).json(result);

  return Response.json(result);
}

and this is my page.tsx where i am trying to acces my own api

export interface TwitchVideoResponse {
  data: TwitchVideo[];
}

export interface TwitchVideo {
  id: string;
  user_name: string;
  title: string;
  url: string;
  thumbnail_url: string;
  type?: string;
  duration?: string;
}

const fetchTwitchVideos = async (user_id: string) => {
  const videos = await fetch(
    `http://localhost:3000/api/twitch?user_id=${user_id}`
  );
  console.log("Twitch Videos:", videos);
  const data: TwitchVideoResponse = await videos.json();
  console.log("Twitch Videos:", data);
  return data;
};

const TwitchPage = async () => {
  const videos: TwitchVideoResponse = await fetchTwitchVideos("1234567890");
  return (
    <div>
      <h1>Twitch Videos</h1>
      {videos.data.map((video: TwitchVideo) => (
        <h1 key={video.id}>{video.title}</h1>
      ))}
    </div>
  );
};

export default TwitchPage;

THE BODY MESSAGE OF RESPONSE

_Response {
    type: 'basic',
    url: 'http://localhost:3000/api/twitch?user_id=1234567890',
    redirected: false,
    status: 500,
    ok: false,
    statusText: 'Internal Server Error',
    headers: _Headers {
      Symbol(headers list): _HeadersList {
        cookies: null,
        Symbol(headers map): Map {
          vary: {
            name: 'vary',
            value: 'RSC, Next-Router-State-Tree, Next-Router-Prefetch'
          },
          date: { name: 'Date', value: 'Wed, 05 Jun 2024 17:19:04 GMT' },
          connection: { name: 'Connection', value: 'keep-alive' },
          keep-alive: { name: 'Keep-Alive', value: 'timeout=5' },
          transfer-encoding: { name: 'Transfer-Encoding', value: 'chunked' }
        },
        Symbol(headers map sorted): null
      },
      Symbol(guard): 'immutable',
      Symbol(realm): null
    },
    body: ReadableStream {
      locked: false,
      Symbol(kType): 'ReadableStream',
      Symbol(kState): {
        disturbed: false,
        state: 'readable',
        storedError: undefined,
        stream: undefined,
        transfer: { writable: undefined, port: undefined, promise: undefined },
        controller: ReadableStreamDefaultController {
          desiredSize: 1,
          Symbol(kType): 'ReadableStreamDefaultController',
          Symbol(kState): {
            closeRequested: false,
            highWaterMark: 1,
            pullAgain: false,
            pulling: false,
            queue: [],
            queueTotalSize: 0,
            started: true,
            stream: TeeReadableStream {
              locked: false,
              Symbol(kType): 'ReadableStream',
              Symbol(kState): {...},
              Symbol(nodejs.webstream.isClosedPromise): {
                promise: Promise {
                  Symbol(async_id_symbol): 179243,
                  Symbol(trigger_async_id_symbol): 178103,
                  Symbol(kResourceStore): {
                    headers: bound a {
                      headers: {...},
                      Symbol(headers list): _HeadersList {...},
                      Symbol(guard): 'none'
                    },
                    cookies: bound f { _parsed: Map {...}, _headers: a {...} },
                    mutableCookies: bound p {
                      _parsed: Map {...},
                      _headers: _Headers {...}
                    },
                    draftMode: tU {
                      isEnabled: false,
                      _previewModeId: 'f7a857a23c02b90a14f8664289afa3df',
                      _mutableCookies: bound p {...}
                    },
                    reactLoadableManifest: {},
                    assetPrefix: ''
                  }
                }
              }
            }
          }
        }
      },

… and the error continues

This error comes from

const videos = await fetch(
    `http://localhost:3000/api/twitch?user_id=${user_id}`
  );
  console.log("Twitch Videos:", videos);  'here'

Can you tell me if my function on GET is correct or not? if not what am i doing wrong

This tells me the request to your API failed with a 500, and the rest of hte error doens’t include the body of the response, if any.

I suspect is one of your throws resulting in an “uncaught error” which’ll cause a 500 and didn’t output the error so we don’t know where it’s failing

Doesn’t tell me anything about your API calls to Twitch and their responses

im still quite unsure about your asking. What is it that you need in order to draft a possible solution?

heres a question:
if you were to display videos of a twitch streamer. How would you do it?
what are the steps you would take in order to display the videos in your own proejct?
if you are familiar with next js, please provide solution according to that :slight_smile:

Exactly what you’ve done

Get a token
Call get videos
Return the videos to the front end

The problem is you are not processing the response HTTP Code and response messages, you are just throw-ing

When you throw you had nothing to catch if so your API returned a 500

You need to catch the response status from the twitch api and catch any response messages to help diagnose why your calls are failing

so

  const tokenResponse = await fetch(`https://id.twitch.tv/oauth2/token`, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: tokenParams,
  });

  if (!tokenResponse.ok) {
    console.error("Failed to fetch access token:", tokenResponse.statusText);
    throw new Error(
      `Failed to fetch access token: ${tokenResponse.statusText}`
    );
  }

  const tokenData = await tokenResponse.json(); 

  const accessToken = tokenData.access_token;

becomes

  const tokenResponse = await fetch(`https://id.twitch.tv/oauth2/token`, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: tokenParams,
  });

  if (tokenResponse.status != 200) {
    console.error("Failed to fetch access token:", tokenResponse.statusText);
    return Response.json({
        error: true,
        note: 'failed to get access token',
        message: await tokenResponse.text()
    });
  }

  const tokenData = await tokenResponse.json(); 

  const accessToken = tokenData.access_token;

Update each API call to return something instead of throwing.
And check the status code not if it was ok

This’ll return a JSON blob to your frontend instead of your backend 500-ing.
Do that for each Twitch API call and you can diagnose which Twitch API call is failing and why it’s failing.

TLDR: you are not catching your throws and logging the throw out somewhere and not collecting the body of the response to help diagnose. So your api is 500-ing with no useful output

appreciate the instant feedback!

i hope i am not disturbing you too much. its kinda an urgent project which my boss needs so please excuse me

i can finally see the error in my terminal

The error message has to do with the token response

HOWEVER i am testing the response on my postman and in my postman i am getting a response (
{
“access_token”: “33134mcm63ki75zq05fwm2gtj33c6wnx”,
“expires_in”: 5418778,
“token_type”: “bearer”
}
)

But when it comes to actual implementation on code it says

Twitch Videos: {
error: true,
note: ‘failed to get access token’,
message: ‘{“status”:400,“message”:“invalid client”}\n’
}
✓ Compiled in 147ms (255 modules)
Twitch Videos: _Response [Response] {
[Symbol(realm)]: { settingsObject: {} },
[Symbol(state)]: {
aborted: false,
rangeRequested: false,
timingAllowPassed: false,
requestIncludesCredentials: false,
type: ‘default’,
status: 200,
timingInfo: null,
cacheState: ‘’,
statusText: ‘’,
headersList: _HeadersList {
cookies: null,
[Symbol(headers map)]: [Map],
[Symbol(headers map sorted)]: null
},
urlList: ,
body: { stream: undefined, source: [Uint8Array], length: 112 }
},
[Symbol(headers)]: _HeadersList {
cookies: null,
[Symbol(headers map)]: Map(6) {
‘connection’ => [Object],
‘content-type’ => [Object],
‘date’ => [Object],
‘keep-alive’ => [Object],
‘transfer-encoding’ => [Object],
‘vary’ => [Object]
},
[Symbol(headers map sorted)]: null
}
}

This is my code again for reference
import { NextRequest, NextResponse } from ‘next/server’;

export async function GET(req: NextRequest) {
try {
const { searchParams } = new URL(req.url);
const user_id = searchParams.get(‘user_id’);
if (!user_id) {
console.error(“User ID not provided”);
return NextResponse.json({ error: “User ID not provided” }, { status: 400 });
}

const client_id = process.env.TWITCH_CLIENT_ID;
const client_secret = process.env.TWITCH_CLIENT_SECRET;

if (!client_id || !client_secret) {
  console.error("Twitch client ID or client secret not found");
  return NextResponse.json({ error: "Twitch client ID or client secret not found" }, { status: 500 });
}

const tokenParams = new URLSearchParams({
  client_id: client_id,
  client_secret: client_secret,
  grant_type: "client_credentials",
});

const tokenResponse = await fetch(`https://id.twitch.tv/oauth2/token`, {
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded",
  },
  body: tokenParams,
});

if (!tokenResponse.ok) {
  console.error("Failed to fetch access token:", tokenResponse.statusText);
  return Response.json({
      error: true,
      note: 'failed to get access token',
      message: await tokenResponse.text()
  });
}

const tokenData = await tokenResponse.json(); 

console.log("Token Data:", tokenData);     

const accessToken = tokenData.access_token;

const appURL = `https://api.twitch.tv/helix/videos?user_id=${user_id}`;
const videoResponse = await fetch(appURL, {
  headers: {
    "Client-ID": client_id,
    Authorization: `Bearer ${accessToken}`,
  },
});

if (!videoResponse.ok) {
  const errorText = await videoResponse.text();
  console.error(`Failed to fetch videos: ${errorText}`);
  return NextResponse.json({ error: `Failed to fetch videos: ${errorText}` }, { status: videoResponse.status });
}

const result = await videoResponse.json();
if (!result.data || result.data.length === 0) {
  console.error("No videos found for the given user ID");
  return NextResponse.json({ error: "No videos found for the given user ID" }, { status: 404 });
}

return NextResponse.json(result);

} catch (error) {
console.error(“Error fetching data from Twitch API:”, error);
return NextResponse.json({ error: “Error fetching data from Twitch API” }, { status: 500 });
}
}

This indicates the ClientID passed to the Get Access Token call was invalid.

So debug why it’s invalid.

Your code for the call looks correct and tests fine for me.

So the issue is whatever you are passing in to tokenParams