0

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}`);
    });
1
  • It looks like your fetch is using https, but I don't see https being set up in your Express app. Without seeing how youtuberRoutes is defined, it's not possible to see whether the URL you're matching is going to match any routes. Commented Apr 3, 2019 at 13:10

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

1 Comment

How to use it please Im lost
0

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`);

...


Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.