0

I know this has been asked and answered before, but I've read a lot of the answers, done a lot of googling and still can't seem to figure out what's going on.

I want to make a todo list app using node and mongodb using docker. I have a docker-compose file like this

local:
  image: local
  ports:
    - "3000:3000"
  volumes:
    - ./:/project
  links:
    - mongo
  # runs nodemon server.js
  entrypoint: ["npm", "run", "start"]
mongo:
  image: mongo:latest
  ports: 
    - "27017:27017"
  volumes:
    - ./data/db:/data/db
  entrypoint: ["mongod", "--port", "27017"]

I was very careful to make sure that I'm connecting mongoose like this mongoose.createConnection('mongodb://mongo:27017'); instead of with localhost. However, when I try to POST to my /tasks route in Postman nothing happens. The whole server.js file is

const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const mongoose = require('mongoose');
const Task = require('./api/models/todoListModel');
const bodyParser = require('body-parser');

mongoose.Promise = global.Promise;
mongoose.createConnection('mongodb://mongo:27017');
// I've also tried mongodb://mongo/local:27017 and /project just in case...
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

const routes = require('./api/routes/todoListRoutes');
routes(app);

app.get('/', (req, res) => {
  res.json({ message: 'At least this works...' });
});

app.listen(port);
console.log(`listening on port ${port}`);

Thanks for any help you can offer!

Update - The answer below is basically correct. I did need to wait for mongo to be up before using the server. But I didn't understand that in this case I could just delay listening on the server to make it work. The following seems to work correctly.

const express = require('express');
const app = express();
const mongoose = require('mongoose');
const mongo = 'mongodb://mongo:27017'

mongoose.connect(mongo);
mongoose.Promise = global.Promise;

const db = mongoose.connection;

db.on('error', (err) => {
  console.log(`DB Error -> ${err}`);
})

app.get('/', (req, res) => {
  res.send('Hello world');
});
/*
Note that the server can be constructed in advance.
It only begins actively listening once the mongo/mongoose connection is fully open.
This way you don't have to use an external script to wait for the ports to open.
*/
db.once('open', () => {
  app.listen(3000, () => {
    console.log('App is listening on 3000');
  });
});
aberkow
  • 330
  • 1
  • 10
  • I forgot to accept the answer below. Sorry @ebnius. The answer was basically right. I just didn't understand that I could use the `once()` method on the mongoose connection to wait for express to start listening. I'm editing my question to show how it should work. – aberkow Mar 23 '18 at 12:39

1 Answers1

1

You have to make sure mongo is up and running before your server is operational. Currently mongo can be in the process of starting when you connect from your server. There are several ways to get around that. Perhaps a shell script that waits for port 27017 before kicking off you npm process. Look at this question for reference How to wait for an open port with netcat?. And this: https://docs.docker.com/compose/startup-order/

Also I don't see a POST route on your server code

ebnius
  • 910
  • 2
  • 8
  • 14
  • This is interesting because I wasn't aware of the timing issues before now. We've been using docker for a LAMP stack and I guess apache is waiting for mysql to start up. Using the `depends_on` key definitely helped, but I need to figure out the other utilities still. As for the POST routes, they're imported from `./api/routes/todoListRoutes` – aberkow Nov 03 '17 at 13:08