MongoDB and Express CRUD
Tags: mongodb, express, crud, javascript
Published: 2022-05-16 02:47:19

## Backend Setup

Create files in the respective directories all under a `backend` folder.

`config/db.js`
`controllers/goalController.js`
`middleware/errorMiddleware.js`
`models/goalModel.js`
`routes/goalRoutes.js`
`server.js`

In the root directory have a `.env` file for db key and other environment variables.

### .env

```
NODE_ENV = development
PORT = 5001
MONGO_URI = <connection to mongoDB uri>
```

### Server.js

Initial config of starting routes for backend.

```JavaScript
const express = require("express");
const colors = require("colors");
const dotenv = require("dotenv").config();
const connectDb = require('./config/db')
const port = process.env.PORT || 5001;
const { errorHandler } = require("./middleware/errorMiddleware");

connectDb()

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.use("/api/goals", require("./routes/goalRoutes"));

app.use(errorHandler);

app.listen(port, () => console.log(`Server start on port ${port}`));
```

## Backend files

### ./config/db.js

```JavaScript
const mongoose = require('mongoose');

const connectDB = async () => {
  try {
    const conn = await mongoose.connect(process.env.MONGO_URI);
    console.log(
      `MongoDB Connected: ${conn.connection.host}`.cyan.underline
    );
  } catch (error) {
    console.log("error", error);
    process.exit(1);
  }
};

module.exports = connectDB;
```

### ./controllers/goalController.js

```JavaScript
const asyncHandler = require('express-async-handler');

const Goal = require('../models/goalModel');

const getGoals = asyncHandler(async (req, res) => {
  const goals = await Goal.find();
  res.status(200).json(goals);
});

const setGoal = asyncHandler(async (req, res) => {
  if (!req.body.text) {
    res.status(400);
    throw new Error("Please add a text field");
  }

  const goal = await Goal.create({
    text: req.body.text,
  });
  
  res.status(200).json(goal);
});
// Other CRUD actions below

module.exports = {
  getGoals,
  setGoal,
  ...
}; 
```

### ./middleware/errorMiddleware.js

```JavaScript
const errorHandler = (err, req, res, next) => {
  const statusCode = res.statusCode ? res.statusCode : 500;
  res.status(statusCode);

  res.json({
    message: err.message,
    stack: process.env.NODE_ENV === "production" ? null : err.stack,
  });
};

module.exports = {
  errorHandler,
};

// "./models/goalModel.js"
const mongoose = require("mongoose");

const goalSchema = mongoose.Schema(
  {
    text: {
      type: String,
      required: [true, "Please add a text value"],
    },
  },
  {
    timestamps: true,
  }
);

module.exports = mongoose.model("Goal", goalSchema);
```

### ./routes/goalRoutes.js

```JavaScript
const express = require("express");
const router = express.Router();
const {
	getGoals,
	setGoal,
	updateGoal,
	deleteGoal,
} = require("../controllers/goalController");

router.get('/', (req, res) => {
  res.status(200).json({ message: "Get goals" });
});

router.post('/', (req, res) => {
  res.status(200).json({ message: "Set goal" });
});

router.put('/:id', (req, res) => {
  res.status(200).json({ message: `Update goal ${req.params.id}` });
});

router.delete('/:id', (req, res) => {
  res.status(200).json({ message: `Delete goal ${req.params.id}` });
});

module.exports = router;
```


Refactor the router methods to clean it up.

```JavaScript
// "./routes/goalRoutes.js"
...

router.route('/').get(getGoals).post(setGoal)
router.route('/:id').delete(deleteGoal).put(updateGoal)

...

```

Generic setup for routes and error handling get things setup for quick. Check with a REST client to verify all routes are working with proper response.

All of the controller actions are asynchronous and will require the use of `async/await`

Making use of express.js is still relatively new to me coming from a Rails background, but the use of JavaScript and the refactoring involved to keep separation of concerns in order is more or less straight forward.