Build REST API with RethinkDB, Node.js and Express.js

Published on June 2, 2020 3 min read

In this guide, we’re going to create REST API with RethinkDB, Node.js and Express.js. I’ll create a books table and will write CRUD operations for books table:

Let’s get started:

Table of Contents

  1. Create Project and Install Dependencies
  2. Configure Database
  3. Modify Index Route
  4. Create Book Route
  5. Modify App.js
  6. Test Our Project

Create Project and Install Dependencies

Install express-generator by running this command:

# with npx
npx express-generator
# with npm
npm install -g express-generator

Let’s create a project called rethinkdb-express-rest-api.

# create project
express --view=ejs rethinkdb-express-rest-api
# go to the project folder
cd rethinkdb-express-rest-api

Install node modules for this app:

npm install --save dotenv rethinkdb

# development dependency
npm install --save-dev nodemon

We’re going to use nodemon as a hot re-loader and need to modify start script like:

package.json
{
  "name": "rethinkdb-express-rest-api",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "start": "nodemon ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "dotenv": "^8.2.0",
    "ejs": "~2.6.1",
    "express": "~4.16.1",
    "http-errors": "~1.6.3",
    "morgan": "~1.9.1",
    "rethinkdb": "^2.4.2"
  },
  "devDependencies": {
    "nodemon": "^2.0.4"
  }
}

Configure Database

In the root path, create these folders & files:

1. .env
2. config/database.js
3. lib/connect.js

Open .env and set RethinkDB server info:

.env
RDB_HOST=172.105.127.15
RDB_PORT=28015
RDB_DATABASE=mnp_test

And paste these codes in database.js and connect.js file.

config/database.js
module.exports = {
  host: process.env.RDB_HOST,
  port: process.env.RDB_PORT
};
lib/connect.js
'use strict';

const r = require( 'rethinkdb' );
const config = require( '../config/database' );

module.exports.connect = function ( req, res, next ) {
    let count = 0;

    ( function _connect() {
        r.connect( config, ( error, connection ) => {
            if ( error && error.name === 'ReqlDriverError' && error.message.indexOf( 'Could not connect' ) === 0 && ++count < 31 ) {
                console.log( error );
                setTimeout( _connect, 1000 );
                return;
            }

            req._rdb = connection;
            next();
        } );
    } )();
};

module.exports.close = function ( req, res, next ) {
    req._rdb.close();
};

Modify Index Route

Navigate to routes folder and open index.js file. We'll add a route here to create a database and table.

routes/index.js
var express = require('express');
var router = express.Router();

// rethinkdb
const r = require('rethinkdb');
var databaseName = process.env.RDB_DATABASE;
var tableName = "books"; // set table name

/* home page */
router.get('/', (request, response ) => {
    response.render('index', { title: 'MyNotePaper' });
});

/* create database and table */
router.get('/create-db-table', (request, response ) => {
    // create db
    r.dbCreate(databaseName).run(request._rdb);
    console.log('Database ' + databaseName + ' created!');

    // create table
    r.db(databaseName).tableCreate(tableName).run(request._rdb);
    console.log('Table ' + tableName + ' created!');

    message = "Successfully created database '" + databaseName + "' & table '" + tableName + "'";

    // render
    response.render('notice', { title: 'RethinkDB', message: message });
});

module.exports = router;

Create Book Route

Go to routes folder and create books.js file. Then paste this code:

routes/books.js
var express = require('express');
var router = express.Router();

// rethinkdb
const r = require('rethinkdb');
var databaseName = process.env.RDB_DATABASE;
var tableName = "books"; // set table name

/* add book */
router.post('/', (request,response ) => {
    let book ={
        'name': request.body.name,
        'author': request.body.author
    };
  
    r.db(databaseName).table(tableName)
        .insert(book)
        .run(request._rdb)
        .then(cursor => cursor.toArray())
        .then( result => {
            // logic if you want to set
        })
        .catch(error => console.log(error));

    // response
    let data = {
        'success': true,
        'message': "Book successfully added",
    };
    response.json(data);
});

/* get all books */
router.get('/', (request,response ) => {

    r.db(databaseName).table(tableName)
        .orderBy(r.desc("id"))
        .run(request._rdb)
        .then(cursor => cursor.toArray())
        .then(result => {
            // logic if you want to set
            response.json(result);
        })
        .catch( error => console.log(error));
});

/* get single book */
router.get('/:book_id', (request,response ) => {
    let book_id = request.params.book_id;

    r.db(databaseName).table(tableName)
        .get(book_id)
        .run(request._rdb)
        .then(result => {
            // logic if you want to set
            response.json(result);
        })
        .catch( error => console.log(error));
});

// update book
router.put( '/:book_id', (request,response ) => {
  let book_id = request.params.book_id;

  r.db(databaseName).table(tableName)
      .get( book_id )
      .update( {
        'name': request.body.name,
        'author': request.body.author
      })
      .run( request._rdb )
      .then(cursor => cursor.toArray() )
      .then(result => {
          response.send(result);
      })
      .catch(error => console.log(error));

      // response
      let data = {
          'success': true,
          'message': "Book successfully updated",
      };
      response.json(data);
});

// delete book
router.delete( '/:book_id', (request,response ) => {
  let book_id = request.params.book_id;

  r.db(databaseName).table(tableName)
      .get(book_id)
      .delete()
      .run(request._rdb)
      .then(cursor => cursor.toArray() )
      .then(result => {
        response.send(result);
      })
      .catch(error => console.log(error));

      // response
      let data = {
          'success': true,
          'message': "Book successfully deleted",
      };
      response.json(data);
});

module.exports = router;

Take a look at the code. I've created all CRUD routes.

Modify App.js

We need to include the books.js route file in app.js. Also, we have to open RethinkDB connection to all routes. Open App.js and add these lines:


var booksRouter = require('./routes/books');

// rethinkdb
const connect = require( './lib/connect' );
app.use( connect.connect ); // open rdb conn

app.use('/', indexRouter);
app.use('/books', booksRouter);

app.use( connect.close ); // close rdb conn

So, the filnal app.js file looks like:

app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
require( 'dotenv' ).config();

// router
var indexRouter = require('./routes/index');
var booksRouter = require('./routes/books');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// rethinkdb
const connect = require( './lib/connect' );
app.use( connect.connect ); // open rdb conn

app.use('/', indexRouter);
app.use('/books', booksRouter);

app.use( connect.close ); // close rdb conn 

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

Test Our Project

Our application is ready to use. Run npm start to run the project. Now test the routes:

Method URL Action
GET /create-db-table create database & table
POST /books add new book
GET /books retrieve all books
GET /books/id retrieve single book
PUT /books/id update single book
DELETE /books/id delete single book

I've tested using Postman. Here's the screenshot of add book route:

That's all. You can download this project from GitHub. Thank you. 🙂

Author

Hey, I'm Md Obydullah. I build open-source projects and write on Laravel, Linux server, modern JavaScript and more on web development. If you enjoy my content, please consider supporting what I do!

Follow Buy me a coffeeBuy me a coffee

Leave a Reply

Your email address will not be published. Required fields are marked *