I'm currently setting up a custom Node server with Next.js. The fact that I'm using Next.js shouldn't make any difference though.
In previous apps, I've always used mongoose.connection.once('open', callback) to start listening only when the database is open. This time, it's not working.
This is my connection configuration file:
import mongoose from 'mongoose';
import { MONGO_URI } from '../constants'; // looks like 'mongodb://localhost/my-db' in development
mongoose
.connect(MONGO_URI, () => {
try {
console.log(`Connected to ${MONGO_URI} with Mongoose.`);
} catch (err) {
throw err;
}
})
export default mongoose.connection;
I am importing this and using it in my main.ts file like so:
import express from 'express';
import next from 'next';
import * as dotenv from 'dotenv';
import logger from 'morgan';
import compression from 'compression';
import helmet from 'helmet';
import rateLimiter from './config/rateLimiter';
import db from './config/connection'; // This is the config file
dotenv.config();
const PORT = process.env.PORT || '8000';
const dev = process.env.NODE_ENV !== 'production';
const nxt = next({ dev });
const handle = nxt.getRequestHandler();
nxt.prepare().then(() => {
const app = express();
app.enable('trust proxy');
app.use(logger('dev'));
app.use(helmet());
app.use(rateLimiter);
app.use(compression());
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
db.once('open', () => {
app.listen(PORT, () => {
// This log never happens
console.log(`Listening on port ${PORT}.`);
});
});
});
It's extremely strange, because "Connected to mongodb://localhost/my-db with Mongoose." is in fact logged when using the code above, but the express app simply never listens; however, when I remove the app.listen out of the db.once callback function, "Listening on port 8000" does of course get logged.
I'm stumped. Why isn't the 'open' event firing? I've verified that mongo is working locally through the Mongo shell, and this same exact code was working when I had the folder which these files are in (server) separate from the Next.js app (when I was still debating which type of view layer to write).
The issue is not compatibility. I'm running Mongo 5.0.5, and Mongoose 6.2.5, which should be find according to this
Please don't link to some other question. None of these have helped:
My mongo is compatible
mongoose.connect doesn't return a promise
The comment from #Shivam Sood was correct. The db.once('open') was being called too late. Once nxt.prepare had happened, the db was already opened.
Here is the modified code:
import express from 'express';
import next from 'next';
import * as dotenv from 'dotenv';
import logger from 'morgan';
import compression from 'compression';
import helmet from 'helmet';
import rateLimiter from './config/rateLimiter';
import db from './config/connection';
dotenv.config();
const PORT = process.env.PORT || '8000';
const dev = process.env.NODE_ENV !== 'production';
const nxt = next({ dev });
const handle = nxt.getRequestHandler();
db.once('open', () => { // Listen for 'open' event before nxt.prepare, and before listening on PORT
nxt.prepare().then(() => {
const app = express();
app.enable('trust proxy');
app.use(logger('dev'));
app.use(helmet());
app.use(rateLimiter);
app.use(compression());
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.get('*', (req, res) => {
return handle(req, res);
});
app.listen(PORT, () => {
console.log(`Listening on port ${PORT}.`);
});
});
});
Related
I have three files when I try running index.js file DB work well but router does not work and if run server.js DB and router does not work
server
import express from 'express'
import cors from 'cors'
import restaurants from './api/restaurants.route.js'
const app = express()
app.use(cors())
app.use(express.json())
app.use("/api/v1/restaurants", restaurants)
app.use("*", (req, res) => res.status(404).json({error: "Not Found"})) // any router not found in our routers
export default app;
index
import app from './server.js'
import mongodb from 'mongodb'
import dotenv from 'dotenv'
dotenv.config()
const mongoClient = mongodb.MongoClient
const port = process.env.PORT || 8000
mongoClient.connect(
process.env.RESTREVIEWS_DB_URI,
{
useNewUrlParser: true,
useUnifiedTopology: true,
}
).catch((e) => {
console.log(e.stack)
process.exit(1)
}).then(async client => {
app.listen(port, () => {
console.log(`app listen in link http://localhost:${port}/api/v1/restaurants`)
})
})
router
import express from 'express'
const router = express.Router();
router.get('/api/v1/restaurants', (req, res) => {
res.status(200).send("HelloWorld");
})
export default router
I know there are several version of this but I can't seem to find a solution for mine.
My server doesn't seem to see all routes in my routes file. It only matches the first one.
index.js
import express from 'express'
import mongoose from 'mongoose'
import dotenv from "dotenv";
import tweetRoutes from "./src/routes/tweetRoutes.js";
dotenv.config();
const app = express();
const PORT = process.env.PORT || 5000;
app.use(express.json());
// Routes
app.use("/api/tweets", tweetRoutes);
// DB connection
mongoose.connect(process.env.DB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
mongoose.connection.on("connected", () =>
console.log("DB Connection Established!")
);
// Server
app.listen(PORT, () => console.log(`Server listening on: ${PORT}`))
tweetRoutes.js
import { Router } from 'express'
import {
createTweet,
fetchTweets,
fetchTweet,
updateTweet,
deleteTweet,
} from "../controller/tweetController.js";
const router = Router();
router.get("/", fetchTweets);
router.get("/:id", fetchTweet);
router.post("/create-tweet", createTweet);
router.patch("/:id", updateTweet); // Not working
router.delete("/:id", deleteTweet); // Not working
export default router;
In this case, the only route accessible is the first one, fetchTweets. Even when I pass an ID param to get a single tweet using the fetchTweet route, it routes to the first route. The other routes return a 404.
What could I be doing wrong? Any help is highly appreciated.
Thank you for providing the url you used to test the fetchTweet route.
You should use the following path instead to reach the desired route:
127.0.0.1:3000/api/tweets/61b9af93e88ee4de51c28b95
Reference:
https://expressjs.com/en/guide/routing.html
I'm using node.js to build a REST CRUD, and to check if my urls are working i'm trying to get a "Hello1" message when I acess the url "localhost:5000/users", but all I get when I acess it is Cannot GET /users. I really don't know what's wrong with my code, because i'm following exactly what the tutorial says. Does anybody know what's going on?
users.js file:
import express from 'express';
const router = express.Router();
router.get('/' , (req,res) => {
res.send("Hello1");
});
export default router;
//////////////////////////////////////
index.js file
import express from 'express';
import bodyParser from 'body-parser';
import usersRoutes from './routes/users.js';
const app = express();
const PORT = 5000;
app.use(bodyParser.json());
app.get('/', (req,res) => {
res.send("hello");
})
app.get('/users', usersRoutes);
app.listen(PORT, () => console.log("Server running on localhost:"+PORT));
Instead of:
app.get('/users', usersRoutes);
You should use:
app.use('/users', usersRoutes);
I have a custom express server that I'm using with NextJS.
Everything works just fine when I'm developing locally, but when I deploy to Vercel, I catch 404s whenever I try to access my backend API.
What could be going wrong? Here's my server.ts:
import express from 'express';
import next from 'next';
import bodyParser from 'body-parser';
import { connectDbs } from './config/db';
import { listingsRouter } from './routes';
const PORT = process.env.PORT || 3003;
const dbs = ['mydb'];
const dev = process.env.NODE_DEV !== 'production';
const nextApp = next({ dev });
const handle = nextApp.getRequestHandler();
const applyMiddleware = (app) => {
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
};
const applyRoutes = (app) => {
app.use('/api/listings', listingsRouter);
};
const startServer = async () => {
await nextApp.prepare();
const app = express();
applyMiddleware(app);
applyRoutes(app);
app.get('*', (req, res) => handle(req, res));
await connectDbs(dbs);
app.listen(PORT, () => console.log(`App listening on port ${PORT}`));
};
startServer();
The Next.js documentation for custom servers:
A custom server cannot be deployed on Vercel, the platform Next.js was made for.
Source: Custom Server
Even though you can't deploy a custom server, you generally don't need to do so because Next.js supports Serverless Functions using the /pages/api directory.
Source: API Routes
Also take a look at this Guide explaining how to convert custom Next.js server to routes:
Source: Server to Routes Guide
I made a server with node js, and my localhost:4000 worked well before. And then, I wrote many codes after it. But my localhost:4000 doesn't work now. Please let me know what's wrong with it.
app.js:
import express from "express";
import morgan from "morgan";
import helmet from "helmet";
import cookieParser from "cookie-parser";
import bodyParser from "body-parser";
import userRouter from "./routers/userRouter";
import videoRouter from "./routers/videoRouter";
import globalRouter from "./routers/globalRouter";
import routes from "./routes";
const app = express();
const PORT = 4000;
function handleListening() {
console.log(`listening http://localhost:${PORT}`);
}
app.listen(PORT, handleListening);
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(helmet());
app.use(morgan("dev"));
app.use("routes", globalRouter);
app.use("routes.users", userRouter);
app.use("routes.videos", videoRouter);
export default app;
init.js:
import app from "./app";
const PORT = 4000;
const handleListening = () =>
console.log(`Listening on: http://localhost:${PORT}`);
app.listen(PORT, handleListening);
Only one process can be bound to a port at a time. You are trying to start your sever twice at port 4000. You should be getting an error saying this.
If you want init.js to handle starting the server, remove
app.listen(PORT, handleListening);
from app.js and you should be good.