loading...
Cover image for Quickly build a blog api with QuickCrud.js

Quickly build a blog api with QuickCrud.js

kingrayhan profile image King Rayhan ・4 min read

Mongoose is one of the best ORM so far for MongoDB. Their crud API is so good but we need to do a lot of repeated things over and over in order to do pagination, sorting and populating. For reducing the pain of your neck, here comes the magical tool QuickCrud.js

Let's quickly build a blog API with QuickCrud.js

Setup Express

Step 1

Install packages

npm init -y

yarn add express mongoose quick-crud

Step 2

Let's setup express server via index.js

const express = require('express')
const app = express()

// Body parser for accepting json from client
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

app.get('/', (req, res) => {
    res.json({
        message: 'QuickCrud.js blog api'
    })
})

// Connect to db via mongoose
mongoose
    .connect(/*db_url*/)
    .then(() => {
        console.log('Database Connected.')
    })
    .catch((error) => {
        console.log('Database Connect Faield.')
    })

// Start server
app.listen(3000, () => {
    console.log('server running on http://localhost:3000')
})

Step 3

Then we will create a directory named models and write 2 model files here.

Post.js

const mongoose = require('mongoose')

const postSchema = new mongoose.Schema({
    title: String,
    body: String,
    categories: [
        // referencing the category model
        {
            type: mongoose.SchemaTypes.ObjectId,
            ref: 'Category'
        }
    ]
})

const Post = mongoose.model('Post', postSchema)
module.exports = Post

Category.js

const mongoose = require('mongoose')

const categorySchema = new mongoose.Schema({
    name: String
})

const Category = mongoose.model('Category', categorySchema)
module.exports = Category

Step 4

Create routes directory and put posts.js and categories.js on it. We will work with these two routes to illustrate QuickCrud.js

At first, let's create posts.js and categories.js base endpoints

// file: routes/posts.js
const Router = require('express').Router()

// Get post list
Router.get('/', (req, res) => {})

// Create a post
Router.post('/', (req, res) => {})

// Get a single post
Router.get('/:_id', (req, res) => {})

// Update a single post
Router.put('/:_id', (req, res) => {})

// Delete a post
Router.delete('/:_id', (req, res) => {})

module.exports = Router
// file: routes/categories.js

const Router = require('express').Router()

// Get category list
Router.get('/', (req, res) => {})

// Create a category
Router.post('/', (req, res) => {})

// Get a single category
Router.get('/:_id', (req, res) => {})

// Update a single category
Router.put('/:_id', (req, res) => {})

// Delete a category
Router.delete('/:_id', (req, res) => {})

module.exports = Router

And the update our index.js file to hook up these routes

const express = require('express')
const app = express()

// Body parser for accepting json from client
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

// Routes
app.use('posts', require('./routes/posts'))
app.use('categories', require('./routes/categories'))

app.get('/', (req, res) => {
    res.json({
        message: 'QuickCrud.js blog api'
    })
})

app.listen(3000, () => {
    console.log('server running on http://localhost:3000')
})

Step 5

Now let's start doing magic with QuickCrud.js. As we are using this magical tool, we no longer need any controller file for routes. We have all sorts of crud functionality on QuickCrud.js out of the box which we have to do repeatedly on controllers.

In QuickCrud.js have 5 methods

  • index() - For fetching all resources with pagination and limiting
  • store() - Create a document
  • show() - Fetch a single resource with schema key
  • update() - Update an existing document
  • destroy() - Delete an existing document

Create category document

Route.post('/', async (req, res) => {
    const _doc = await qc.store(Category, req.body)
    res.json(_doc)
})

Response

{
    "_id": "xxx",
    "name": "cat 1",
    "__v": 0
}

Get All categories

For getting all categories, we have qc.index() method.

Route.get('/', async (req, res) => {
    const _docs = await qc.index(Category)
    res.json(_docs)
})

Response

Limiting and paginating with ?page and ?limit
qc.index() method have 3 args: Model, Population, PagitionOption.

With PagitionOption of qc.index() we can do pagination and limiting resources list.

Route.get('/', async (req, res) => {
    const _docs = await qc.index(Category, {} , {
        page: +req.query.page,
        limit: +req.query.limit
    })
    res.json(_docs)
})

?limit=3&page=1

Page1

?limit=3&page=2
Page2

Update and Delete category

Updating and deleting is pretty straight forward with qc.destroy() and qc.update()

// Update a single category
Route.put('/:_id', async (req, res) => {
    let data = await qc.update(
        Category,
        {
            _id: req.params._id
        },
        req.body
    )

    res.json({
        message: 'Category updated',
        data
    })
})

// Delete a category
Route.delete('/:_id', (req, res) => {
    let data = await qc.destroy(Category, {
        _id: req.params._id
    })

    res.json({
        message: 'Category deleted',
        data
    })
})

Post endpoints

As like previous categories route, post's update and delete is dead simple and straight forward.

// Update a single post
Router.put('/:_id', (req, res) => {
    let data = await qc.update(
        Post,
        {
            _id: req.params._id
        },
        req.body
    )

    res.json({
        message: 'Post updated',
        data
    })
})

// Delete a post
Router.delete('/:_id', (req, res) => {
    let data = await qc.destroy(Post, {
        _id: req.params._id
    })

    res.json({
        message: 'Post deleted',
        data
    })
})

Lets create some posts with categories

create post

Now lets fetch all and single resource with categories population

// Get post list
Router.get('/', async (req, res) => {
    const _docs = await qc.index(Post, {} , {
        page: +req.query.page,
        limit: +req.query.limit
    } , 'categories')
    res.json(_docs)
})

// Get a single post
Router.get('/:_id', async (req, res) => {
    const _docs = await qc.show(Post, { _id: req.params._id }, 'categories')
    res.json(_docs)
})

Post list with categories population
Post list with categories population

Single post with categories population
Single post with categories population

Want to explore more?
Checkout package documentation: https://www.npmjs.com/package/node-crud

Feel free to report any type of bug report or feature request.

GitHub logo kingRayhan / quick-crud

An easy CRUD operation based on Factory pattern with Mongoose.

QuickCrud.js

Installation

npm i quick-crud

or

yarn add quick-crud

An easy CRUD operation based on Factory pattern with Mongoose. There are four CRUD operations we can do:

  • index({model, where, populateOptions, paginationOptions}) : Fetch all documents with pagination.

    • model - Mongoose model.
    • where - MongoDB filter object.
    • populateOptions - Mongoose population object/string.
    • paginationOptions can get three parameters
      • limit:number - Resource count to show. Default is 10
      • page:number - Pagination page number. Default is 1.
      • sort:string - MongoDB property sort key. Default is '-createdAt'
  • store({model, data}) - You can create a doc and store it to MongoDB.

    • model - Mongoose model.
    • data - An object of data to store in MongoDB based on Mongoose Schema
  • show({model, where, populationOptions}): Fetch a single document via filter key.

    • model - Mongoose model.
    • where - MongoDB filter object.
    • populateOptions - Mongoose population object/string.
  • update({model, where, data}) - updates the first document that matches where

Source code

Discussion

pic
Editor guide