Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Next.js API and DB Connections Issue

Should I reconnect to the DB in every handler when I use next.js for API? Or is there a better way to do that?

And isn't that a bad thing if it was the regular approach?

I tried to create a nextjs project with typeorm or MongoDB and all the examples and resources look like they are waiting for the connection with each call. enter image description here

The attached image is for typeorm example. I got it from this repo

And here is the Mongo articles that I found that they instruct to add the DB connection in middleware and recall it in every handler.

https://developer.mongodb.com/how-to/nextjs-building-modern-applications https://hoangvvo.com/blog/full-fledged-app-with-next-js-and-mongodb-part-1/

and here is the repos middleware to check it too if you like

https://github.com/kukicado/building-modern-app-with-nextjs-and-mongodb/blob/master/mct/middleware/database.js

https://github.com/hoangvvo/nextjs-mongodb-app/blob/master/middlewares/database.js

For me am trying to create nextjs with typeorm but I searched for the Mongo because I couldn't find a lot of resources for typeorm + nextjs so I searched for the connection concept for the Monog since it's kinda similar

like image 274
user8760832 Avatar asked Jun 25 '20 06:06

user8760832


People also ask

Is next js good for API?

Not only is Next. js great for creating serverless API routes, it's also a framework for React. This means that you can create your frontend site and backend logic within the same project.

Are Next js API routes serverless?

Next. js has support for API Routes, which let you easily create an API endpoint as a Node. js serverless function.


2 Answers

I usually create a simple wrapper function for Next API Handlers and use it like

export default withDb((req, res) => {
    // ...
})

withDb function checks if there is an active connection and if not it creates one and uses it for the current and next requests. If there are multiple requests concurrently, it attaches them to the same promise object and waits for the db connection only once. It's like this:

import '@/types';
import mongoose from 'mongoose';
import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
import { Maybe } from '@/types';
import models from '../models';

declare module 'http' {
  interface IncomingMessage {
    models: Maybe<typeof models>;
  }
}

const readyStates = {
  disconnected: 0,
  connected: 1,
  connecting: 2,
  disconnecting: 3,
};

let pendingPromise: Maybe<Promise<typeof mongoose>> = null;

// https://hoangvvo.com/blog/migrate-from-express-js-to-next-js-api-routes/
const withDb = (fn: NextApiHandler) => async (
  req: NextApiRequest,
  res: NextApiResponse,
) => {
  const next = () => {
    req.models = models;
    return fn(req, res);
  };

  const { readyState } = mongoose.connection;

  // TODO: May need to handle concurrent requests
  // with a little bit more details (disconnecting, disconnected etc).
  if (readyState === readyStates.connected) {
    return next();
  } else if (pendingPromise) {
    // Wait for the already pending promise if there is one.
    await pendingPromise;
    return next();
  }

  pendingPromise = mongoose.connect(process.env.DB, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useCreateIndex: true,
    useFindAndModify: true,
  });

  try {
    await pendingPromise;
  } finally {
    pendingPromise = null;
  }

  // We need to return "next" from "withDb". Otherwise, if it wraps an async function,
  // the wrapper function of "withDb" (like "handleErrors" etc)
  // can't wait and catch errors inside it the function wrapped by "withDb".
  // It just waits for "withDb" to complete and continues.
  // As an alternative, we can "await" this "next" too of course.
  // Main point is, waiting it to be completed.
  return next();
};

export default withDb;

As you can see, this example is for mongoose. I've tried using TypeORM with Next.js a couple of times but it creates a lot of problems. I just think I'm gonna try prisma for the next time. TypeORM is cool and a lot more popular. But there are some problems and when you can't solve them, you get stuck at one point.

like image 163
Onur Önder Avatar answered Oct 03 '22 11:10

Onur Önder


I usually connect and disconnect to the database for each API call.

Here are my reasons:

  • When many people will use the site, the number of database connections increases and remains (connection pooling).

  • Reusing database connections removes the need to create a connection for each handler but places a strain on the Node.js server and database server.

Unless you have a specific reason, it may be better to recreate the instance.

like image 29
Moootoko Avatar answered Oct 03 '22 12:10

Moootoko