Exploring the Power of Vercel Deployment: Crafting a Custom CORS Middleware for Your API

Recently, I have been testing different methods to avoid a CORS error in my upcoming app deployed on Vercel. The only solution that worked for me was manually setting the headers for each API request, as shown below:

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  res.setHeader('Access-Control-Allow-Credentials', 'true')
  res.setHeader('Access-Control-Allow-Origin', '*')
  res.setHeader('Access-Control-Allow-Methods', 'GET')
  res.setHeader(
    'Access-Control-Allow-Headers',
    'Origin, X-Requested-With, Content-Type, Accept, Authorization'
  )

  // Handling pre-flight requests
  if (req.method === 'OPTIONS') {
    res.status(200).end()
    return
  }

  let houses: House[] = []

  try {
    await client.connect()
    console.log('Successfully connected to MongoDB')

    const db = client.db('vroom')
    const housesCollection = db.collection('houses')

    houses = (await housesCollection.find().toArray()).map((house) => ({
      house: house.house,
      price: house.price,
      timestamp: house.timestamp,
      developer: house.developer,
    }))

    console.log('Retrieved houses:', houses)
  } catch (error) {
    console.error(`Error while connecting to MongoDB: ${error}`)
  } finally {
    await client.close()
  }

  res.json({ houses })
}

Is there a way to achieve the same outcome using the middleware.ts file or by implementing wrapper code? I would appreciate any guidance on this matter.

Feel free to ask for clarification if needed!

Thank you!

I attempted the above steps but had to include some text here :)

Answer №1

If you're looking to enable CORS in your Next.js application, you have a couple of options. One approach is to utilize the Nextjs-Cors package, or alternatively, you can implement your custom middleware as shown below.

To create a CORS middleware, you can start by creating a middleware.ts (or .js) file at the same hierarchical level as your pages directory within the root or src directory.

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import NextCors from 'nextjs-cors';

export async function middleware(req: NextRequest) {
  const res = NextResponse.next()
  // Execute the CORS middleware
  await NextCors(req, res, {
    // Configuration options
    methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'],
    origin: '*',
    optionsSuccessStatus: 200,
  });
  return res
}

https://www.npmjs.com/package/nextjs-cors

# Installation using npm
npm install --save nextjs-cors@latest

# Installation using yarn
yarn add nextjs-cors@latest

# Installation using pnpm
pnpm add nextjs-cors@latest

Implementing Custom CORS Logic (without dependencies)

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(req: NextRequest) {
  const res = NextResponse.next()
  res.setHeader('Access-Control-Allow-Credentials', 'true')
  res.setHeader('Access-Control-Allow-Origin', '*')
  res.setHeader('Access-Control-Allow-Methods', 'GET')
  res.setHeader(
    'Access-Control-Allow-Headers',
    'Origin, X-Requested-With, Content-Type, Accept, Authorization'
  )

  // Handling pre-flight requests
  if (req.method === 'OPTIONS') {
    return new NextResponse('ok',{status:200})

  }

  return res
}

Answer №2

After encountering a CORS error with my APIs, I found a workaround by creating a middleware wrapper to handle it:

Here's the code from my utils/middleware.ts file:

import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import Cors from 'cors'

const corsMiddleware = Cors({
  methods: ['GET', 'OPTIONS', 'HEAD'],
})

const runMiddleware = (
  req: NextApiRequest,
  res: NextApiResponse,
  fn: Function
) => {
  return new Promise((resolve, reject) => {
    fn(req, res, (result: any) => {
      if (result instanceof Error) {
        return reject(result)
      }

      return resolve(result)
    })
  })
}

export const withCors =
  (handler: NextApiHandler) =>
  async (req: NextApiRequest, res: NextApiResponse) => {
    await runMiddleware(req, res, corsMiddleware)

    if (req.method === 'OPTIONS') {
      res.status(200).end()
      return
    }

    return handler(req, res)
  }

You can use this middleware in your code like this:

import { NextApiRequest, NextApiResponse } from 'next'
import { connectToDB, paginateCollection, withCors } from '@/utils'

export type House = {
  house: string
  price: string
  timestamp: string
  developer: string
}

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  const page = parseInt(req.query.page as string) || 1
  const perPage = 10

  let houses: House[] = []
  let totalPages = 1

  try {
    const db = await connectToDB()

    const housesCollection = db.collection('foo')

    const { items, totalPages: pages } = await paginateCollection(
      housesCollection,
      page,
      perPage
    )
    totalPages = pages

    houses = items.map((house) => ({
      house: house.house,
      price: house.price,
      timestamp: house.timestamp,
      developer: house.developer,
    }))
  } catch (error) {
    console.error(`Error connecting to MongoDB: ${error}`)
  }

  res.json({ houses, totalPages })
}

export default withCors(handler)

Hopefully, this solution proves useful for others facing similar challenges!

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

Flux Utils identified an issue stating that the Class constructor App cannot be called without the 'new' keyword

Struggling to set up a Flux Util container for this React component: class App extends React.Component<{},AppState> { constructor(props:Readonly<{}>){ super(props); } static getStores(){ return [ArticlesStore]; } static calcul ...

Greetings, I am currently utilizing Express along with MongoDb in my project. Every time I attempt to make a post request, I encounter an error message stating that the message (created using

Every time I try to make a post request, I keep getting an error message saying that "message is not a constructor". In this scenario, the message refers to a model that I created using mongoose. I have exported this model using module.exports = message an ...

There was a problem with Type TS2507: The Type 'typeof Tapable' cannot be used as a constructor function type

After creating my own TypeScript library for shared TS models, I wanted to incorporate it into a couple of other projects I'm working on. Here are the essential parts of the library repository: index.ts: export interface IApp { ... } package.json: ...

Discovering the current page using ons-navigator in Onsen UI

I am currently attempting to determine the page I am on while using the popPage() function with Onsen UI's ons-navigator. I have tried the following methods, but they always return false regardless: this.navigator.nativeElement.popPage().then((page: a ...

Sharing data between app.js and client-side files in Node.js: How to do it effectively?

I have a question about passing a value from my Node.js app.js file to my client-side JavaScript file. Here is my app.js file: var express = require('express'); var app = express(); var port = process.en ...

Switch up your Next.js game by altering the Div color of your header based on the active page!

In the Next.js project I've been working on, I created a simple Layout.js file with the code shown below: import { Fragment } from "react"; import Header from "./Header/Header"; import Footer from "./Footer/Footer"; fun ...

What causes express.Router() to malfunction?

I wanted to try out the sample code bird.js from https://expressjs.com/en/guide/routing.html. The code snippet looks something like this: var express = require('express') var router = express.Router() router.use(function timeLog (req, res, next ...

Node Express - Securely storing and accessing authentication tokens

I have set up an Express application and I need guidance on how to securely store tokens. After authenticating a user account, I receive an access token from an OAuth 2 server, which I then need to use for subsequent API requests. To protect the token va ...

Exploring the Differences Between API Routes and getStaticProps

Forgive my confusion, but I'm struggling to grasp the distinction between the two. So, with getStaticProps, you can fetch data and display it on the site. But isn't that the same as using API routes? In both cases, you're fetching data from ...

What could be causing the discrepancy in alignment between a web application running on Mac and Windows using ReactNative?

We have a web application built with react native. The alignment of the columns in the list is causing issues when running the app on Windows versus Mac, as illustrated in the screenshots. Interestingly, this problem only occurs with this specific list tha ...

Is the order of query execution being altered when using the MongoClient in Node.js?

I am currently developing a registration API endpoint that utilizes MongoDB to validate two specific conditions: If the username provided already exists in the database, it will return a status of 500 If the email address provided already exists in the da ...

The module "jquery" in jspm, jQuery, TypeScript does not have a default export

Having some trouble setting up a web app with TypeScript and jspm & system.js for module loading. Progress is slow. After installing jspm and adding jQuery: jspm install jquery And the initial setup: <script src="jspm_packages/system.js"></scri ...

A step-by-step guide on assigning values to an Angular Material Auto Complete component in Angular 7

Hey there! I'm currently using the Angular Material Auto complete component in my Angular 7 app and I'm trying to find a way to bind a value from an API response to it. Can someone help me out with a solution for this? HTML: <mat-form-field> ...

Utilizing React Typescript for Passing Props and Implementing them in Child Components

I'm currently working with React and TypeScript and attempting to pass data as props to a child component for use. However, I've encountered an error that I can't quite understand why it's happening or how to resolve it. Additionally, I ...

Using Arrow Functions in Angular 2 Typescript with Support for IE11

Are arrow functions in Typescript for Angular2 compatible with IE 11? I have come across information stating that arrow functions in javascript may not be supported in IE 11, but I am uncertain if the same applies to Typescript. ...

Are there any security measures integrated into ExpressJS?

In my quest for information, I scoured the documentation but unfortunately found no details on the security measures offered by ExpressJS. As I am more familiar with Node's HTTP module, I presume that is what I will be comparing it to ...

Tips for customizing an image within the antd upload component

Using the upload feature within an antd form component has presented me with a challenge. <Form name="posting" onFinish={onSubmitForm} scrollToFirstError encType='multipart/form-data' > <Form.Item name=&qu ...

The toggle-input component I implemented in React is not providing the desired level of accessibility

Having an accessibility issue with a toggle input while using VoiceOver on a Mac. The problem is that when I turn the toggle off, VoiceOver says it's on, and vice versa. How can I fix this so that VoiceOver accurately states whether the toggle is on o ...

Tips for separating provider and input components with React Hook Form

Currently, I am working on a project with Next 13.5 using react-hook-form and shadcn-ui. The issue that I have encountered is that creating a form involves too much redundant code. To address this, I abstracted the FormProvider and Input component. The pr ...

Checking for GitHub API connectivity issues with GitHub can be done by verifying whether the GitHub API is

Is there a way to check from the GitHub API if it is unable to connect to GitHub or if the internet is not connected? When initializing the API like this: GitHubApi = require("github"); github = new GitHubApi({ version: "3.0.0" ...