Fetching the Twitter API using Next.js API routes

Fetching the Twitter API using Next.js API routes

ยท

4 min read

The problem

When I was playing around with the Twitter API, I found that they did not have CORS headers enabled. The error message shown by them was:

Failed to load https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=nimaiwalsh: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 400. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled

courtesy to this question on freecodecamp

Because I was pretty new to the concept, I searched about what exactly was happening on Stack Overflow. Apparently, the Twitter API did not support CORS, for security purposes. This seems completely normal considering that it is one of the security implementations added to prevent leakage of API keys. As a temporary workaround, I embedded this solution to my code. However, it only gave me access to the proxy server for a few hours. Realizing that it won't work if I deploy the app, I quickly made a Reddit post and asked about what my approach should be to the said problem.

And... voila! A very genuine Redditor gave me the idea of using Next API routes, as they don't send requests from the browser, but instead from a server.


How I did it

When I tried to search for solutions for this specific problem, barely any showed up on the search results. To make sure that does not happen to anyone else, I decided to write this blog. In this example, we will be making an app which fetches Twitter Spaces from the Twitter API using keywords.

To see how I did it, follow the steps mentioned below - with code snippets


1. Go to your pages/api/hello.js file, and fiddle around with this block of code:

export default function handler(req, res) {
  res.status(200).json({ name: 'API route' })
}

When we visit localhost:3000/api/hello, we will see {name: 'API route'} on the screen.


2. Declare an async getSpaces function, which calls the API. The code will look something like this:

 async function getSpaces(req, res) {
        const bearerToken = "BEARER_TOKEN"
        const url = `https://api.twitter.com/2/spaces/search?query=${`Hashnode`}&space.fields=title,host_ids,speaker_ids,participant_count`;

        const response = await fetch(url, {
          headers: {
            Authorization:
              `Bearer ${bearerToken}`,
          },
        });
        const data = await response.json();
        const spaceValue = data.data
        return spaceValue;
      }

What this function does is GET all the spaces, whether scheduled or live, from the Twitter API. The spaceValue variable returns all the spaces in an array, which can later be mapped on the frontend using the map method.


3. Now, we call another function which calls the getSpaces function, and returns the returned data, which is spaceValue, in another variable called spaces.

async function showResult() {
          const spaces = await getSpaces();

          return spaces;
        }

4. Now, we store both of these functions inside a parent handler function.

export default async function handlerI(req, res) {

 // const comment = req.body.query  
// This can later be used to fetch the desired value inputted by the user.
// we send that value using a POST request to this API route, and store it in a variable.
// then, it can be used instead of the hard-coded hashnode query in the URL


     async function getSpaces(req, res) {
        const bearerToken = "BEARER_TOKEN"
        const url = `https://api.twitter.com/2/spaces/search?query=${`Hashnode`}&space.fields=title,host_ids,speaker_ids,participant_count`;

        const response = await fetch(url, {
          headers: {
            Authorization:
              `Bearer ${bearerToken}`,
          },
        });
        const data = await response.json();
        const spaceValue = data.data
        return spaceValue;
      }

  //retrieve results
        async function showResult() {
          const spaces = await getSpaces();

          return spaces;
        }

  const response = await showResult();
  console.log(comment)
  console.log(response)

  res.status(200).json({ name: `Data from Twitter API`, data: response });

}

Hurray!

We successfully completed the backend code. Now, when we send a GET request to /api/hello, we get all the data from the Twitter API fetched by the server.

Sample Data:

[
    {
        "participant_count": 0,
        "state": "scheduled",
        "host_ids": [
            "3957817872"
        ],
        "id": "1RDxlgBZobRJL",
        "title": "๐Ÿ˜Ž How to Become a Web3 Developer"
    }
]

The only thing that would be left to do is add some front-end logic, which can efficiently display the data.

Thank you for reading this far. I'm new to web development, and if I used any terms / explained anything incorrectly, please do make sure to reach out to me at Reddit. Once I make a good UI for this, I'll update the blog with the GitHub repository link for these files. It will also contain other stuff like sending a POST request to the API route to set a value desired by the user.

Hope this helped. Have a good day! :D

ย