In the part one of this article, we covered setting up sequelize, creating migrations/models and seeding the database. In this part, we'll be performing CRUD building on part one.

If you want to follow along, you can start from part one, if you have not done so, but you are free to jump to this part if you're already comfortable with step one.

You can clone the complete code for this article here

Installing Dependencies

 npm i express

We need to install nodemon which restarts the server each time there's a change hence easing the stress of manually restarting the server.

 npm i -D nodemon

Notice the -D flag which indicates that package is only needed in a development environment.

Express Server Setup

To set up the server, we need to create two directories - server and routes:

mkdir server routes

Create an index.js file in each of server and routes directory:

touch server/index.js routes/index.js

Add the following code to routes/index.js

const { Router } = require('express');

const router = Router();

router.get('/', (req, res) => res.send('Welcome'))

module.exports = router;

Add the following code to server/index.js

const express = require('express');
const routes = require('../routes');

const server = express();
server.use(express.json());

server.use('/api', routes);

module.exports = server;

Next up, we create the app entry point at the root of the project:

touch index.js

Add the following code to the index.js

require('dotenv').config();

const server = require('./server');

const PORT = process.env.PORT || 3300;

server.listen(PORT, () => console.log(`Server is live at localhost:${PORT}`));

Finally, we add the start script to the package.json

Add the following code to package.json

 "scripts": {
    "start-dev": "nodemon index.js"
  },

To start the server run

npm start-dev

Now visiting localhost:3300/api on POSTMAN will return "Welcome" which shows that the server is up and running.

Creating a new post [C IN CRUD]

First of all, let's create a new file controllers/index.js which will house the CRUD logics.

mkdir controllers && touch controllers/index.js

Add the following code to the controllers/index.js

const models = require('../database/models');

const createPost = async (req, res) => {
  try {
    const post = await models.Post.create(req.body);
    return res.status(201).json({
      post,
    });
  } catch (error) {
    return res.status(500).json({error: error.message})
  }
}

module.exports = {
  createPost,
}

Next up, we need to create the route for creating new post. Edit the routes/index.js as follows:

const { Router } = require('express');
const controllers = require('../controllers');

const router = Router();

router.get('/', (req, res) => res.send('Welcome'))

router.post('/posts', controllers.createPost);

module.exports = router;

Now when you visit the Create Post Endpoint [POST] localhost:330/api/posts on Postman and fill in the appropriate values for the request body, a new post will be created as shown in the screenshot below:

create post

Getting a list of posts [R in CRUD]

We are going to create another endpoint for retrieving the list of posts. Here we'll apply the eager loading feature of ORM provided by Sequelize. Eager loading means retrieving the associated models along side the model being queried. In Sequelize, eager loading is achieved using the include property as shown in the snippet below.

Add the code following to controllers/index.js.

const getAllPosts = async (req, res) => {
  try {
    const posts = await models.Post.findAll({
      include: [
        {
          model: models.Comment,
          as: 'comments'
        },
        {
          model: models.User,
          as: 'author'
        }
      ]
    });
    return res.status(200).json({ posts });
  } catch (error) {
    return res.status(500).send(error.message);
  }
}

Export the getAllPosts by adding it to the module.exports object.

module.exports = {
  createPost,
  getAllPosts
}

Next up, define the endpoint by adding the following code to routes/index.js:

router.get('/posts', controllers.getAllPosts);

Now, when you visit the Get All Post Endpoint [GET] localhost:330/api/posts on Postman, the response is as shown below.

get all posts
Notice that each post has an array of comments and the author object associated with it, that's eager loading

Getting a single post [R in CRUD]

Sequelize provides a method findOne for retrieving a single record based on a given property of the model.

Add the following code to the controllers/index.js

const getPostById = async (req, res) => {
  try {
    const { postId } = req.params;
    const post = await models.Post.findOne({
      where: { id: postId },
      include: [
        {
          model: models.Comment,
          as: 'comments',
          include: [
           {
            model: models.User,
            as: 'author',
           }
          ]
        },
        {
          model: models.User,
          as: 'author'
        }
      ]
    });
    if (post) {
      return res.status(200).json({ post });
    }
    return res.status(404).send('Post with the specified ID does not exists');
  } catch (error) {
    return res.status(500).send(error.message);
  }
}

Next up, we create the endpoint by adding the following code to routes/index.js

router.get('/posts/:postId', controllers.getPostById);

Now, when you visit [GET] localhost:330/api/posts/1 on Postman, the response is as shown below.

single post
Looking at the response, we used nested eager loading to get the author of a post's comment

Updating a post [U in CRUD]

The update method in Sequelize updates the given model's fields specified in the object passes to it as a parameter. This reduces the stress of manually checking the object passed to the update method and updating the model's field accordingly.

Add the following code to controllers/index.js

const updatePost = async (req, res) => {
  try {
    const { postId } = req.params;
    const [ updated ] = await models.Post.update(req.body, {
      where: { id: postId }
    });
    if (updated) {
      const updatedPost = await models.Post.findOne({ where: { id: postId } });
      return res.status(200).json({ post: updatedPost });
    }
    throw new Error('Post not found');
  } catch (error) {
    return res.status(500).send(error.message);
  }
};

Then, we create the endpoint by adding the following code to routes/index.js

router.put('/posts/:postId', controllers.updatePost);

Deleting a post [D in CRUD]

Sequelize provides a method destroy for deleting a model's record.

Add the following code to controllers/index.js

const deletePost = async (req, res) => {
  try {
    const { postId } = req.params;
    const deleted = await models.Post.destroy({
      where: { id: postId }
    });
    if (deleted) {
      return res.status(204).send("Post deleted");
    }
    throw new Error("Post not found");
  } catch (error) {
    return res.status(500).send(error.message);
  }
};

Then update the routes/index.js with the DELETE as shown below:

router.delete('/posts/:postId', controllers.deletePost);

Conclusion

We have been able to implement CRUD using Sequelize. However in a bid to keeping it simple, we have skipped some parts such as form input validation, error handling, proper separation of concerns. Hence, you could decide to take it further and make those improvements.

Feel free to reach out to me via any means you find convenient if you have any question or some contributions to making the article better.

Suggested resources