Leonardo Drici
Leonardo Drici

Reputation: 789

Link next.js to mongodb with express api

I just got into Next.js and I cannot figure out how to connect my next.js app with my express api. I was able to make it work but I'm pretty sure this is not the right way to implement it since in my Index component I hard coded the fetch url and I know that in production if the port is not the same it won't work.

I tried to put only the route and the fetch API doesn't allow me to do so.

My index page looks like so

import Link from "next/link";
import fetch from "isomorphic-unfetch";

const Index = props => (
  <>
    <h1>Youtubers</h1>
    <ul>
      {props.youtubers.map(youtuber => (
        <li key={youtuber._id}>
          <Link as={`/p/${youtuber._id}`} href={`/post?id=${youtuber.id}`}>
            <a>{youtuber.name}</a>
          </Link>
        </li>
      ))}
    </ul>
  </>
);

Index.getInitialProps = async function() {
  //                this url I think is wrong ↓
  const res = await fetch("https://localhost:5000/youtuber");
  const data = await res.json();

  return {
    youtubers: data.youtubers
  };
};

export default Index;

And in my server.js I have this inside the app.prepare().then()

server.use(bodyParser.urlencoded({ extended: false }));
    server.use(bodyParser.json());

    mongoose.connect(process.env.MONGODB_PASSWORD, {
      useNewUrlParser: true,
      useCreateIndex: true
    });

    mongoose.connection.on("open", function() {
      console.log("mongodb is connected!!");
    });

     mongoose.connection.on(
      "error",
      console.error.bind(console, "MongoDB connection error:")
    );

    //CORS handler
    server.use((req, res, next) => {
      res.header("Access-Control-Allow-Origin", "*");
      res.header(
        "Access-Control-Allow-Headers",
        "Origin, X-Requested-With, Content-Type, Accept, Authorization"
      );
      if (req.method === "OPTIONS") {
        res.header(
          "Access-Control-Allow-Methods",
          "PUT, POST, PATCH, DELETE, GET"
        );
        return res.status(200).json({});
      }
      next();
    });

    //Question Route
    server.use("/youtuber", youtuberRoutes);

    server.get("*", (req, res) => {
      return handle(req, res);
    });

    server.listen(port, err => {
      if (err) throw err;
      console.log(`> Ready on http://localhost:${port}`);
    });

Upvotes: 0

Views: 1921

Answers (2)

Chris Nguyen
Chris Nguyen

Reputation: 2900

which Nextjs version do you use? if it's v9, you can use this https://nextjs.org/docs#api-middlewares to provide your end-point.

Hope to help you.

@Jonney Shih you can create HOC and use it like this:

import mongoose from 'mongoose'

const withConnect = handler => async (req, res) => {
  if (!mongoose.connection.readyState) {
    const uri = 'mongodb+srv://YOUR-CONNECTION'
    await mongoose.connect(uri, {
      useNewUrlParser: true,
      autoIndex: false
    })
  }

  return handler(req, res)
}

export default withConnect

and use it in pages/api/YOUR-ENDPOINT-HERE

import withConnect from '../../../../hoc/withConnect'
import YOUR-SCHEMA from '../../../../models/SCHEMA-NAME.schema'

const handler = async (req, res) => {
  // check req method
  if (req.method === 'POST') {
    // Use your schema here e.g:
    const users = await User.find().exec()

    return SOMETHING
  }

  return SOMETHING
}

export default withConnect(handler)

NOTE: Maybe you need to check model exist like this:

const User: IUserModel = models.User || model('User', userSchema)

Have fun

Upvotes: 1

jkrat
jkrat

Reputation: 158

I was able to make it work but I'm pretty sure this is not the right way to implement it since in my Index component I hard coded the fetch url and I know that in production if the port is not the same it won't work.

To make the url dynamic so it works in dev and production, you can capture the full url in _app.js getInitialProps and then pass that into your index component's getInitialProps for use.

_app.js

import get from 'lodash/get';

...

static async getInitialProps({ Component, ctx }) {
    const serverUrl = ctx.req ? `${ctx.req.protocol}://${ctx.req.get('Host')}` : '';

...

   if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps({ serverUrl });
    }

   return { pageProps };
}

...

index.js

...

static async getInitialProps({ serverUrl }) {
    const res = await fetch((`${serverUrl}/youtuber`);

...


Upvotes: 0

Related Questions