Redis OM: Developer Experience using Node.Js
Tags: redis, javascript, node, programming
Published: 2022-09-21 15:37:10

Using Redis database just for cache is like using a modern mobile phone just for phone calls! You are missing out on a ton of cool things it can do! Give it a try! - **Raja Rao**, _**(VP of Growth Marketing at Redis)**_

I couldn't agree more with **Raja**. There is a whole lot one can do with Redis, why limit yourself. Since I started using the Redis database to manage my data, first it improved my application speed, and I have learned a lot about Redis Stacks and Redis Cloud. In this tutorial, I will share my experience with you. We will go over how  to create records in JSON format using the RedisJSON, index and search records using  the RediSearch stacks. You can read my other blog [How To Store And Retrieve RedisJSON on Redis Cloud using Node.js](https://dev.to/tochine/how-to-store-and-retrieve-redisjson-on-redis-cloud-using-nodejs-42o2) where I threw some light about the gains of using Redis and Redis Cloud.

##### Redis OM 

Redis OM is the magic stick  developers can use to create data model on our applications and map it to the Redis database. Just like Mongoose, with Redis OM we can create models that interact with the database. This tool makes us (Software Developers) have a better experience while using Redis on our application.


##### Goal 

The aim of this tutorial is to learn how to use the Redis technologies to store our data on the Redis cloud while utilizing its high throughput and low latency. We will be creating a Digital Book Library API using NodeJs. The library database will contain a book entity.


##### Prerequisite

* Node Engine
* Yarn or NPM installer
* IDE (E.g: Visual Studio Code)

##### Setup Redis Cloud Account

You can use this link [Redis Cloud](https://redis.com/try-free/?utm_campaign=write_for_redis) to create a free account. After registration click on the ``New subscription`` button to set up a plan. If you're new to Redis you can start with a free subscription to get yourself familiarised with the platform or you can pick a paid plan. For this tutorial, I am using the AWS vendor but you can choose other vendor you're more comfortable with. After creating a subscription you can go ahead and create a database. When creating a database, there is a `` type`` with three options for you to select from. For this tutorial we will be using the Redis Stack Modules. 

Redis Stack gives you a software development experience by enabling you to create data models and map them to your database. With RedisJSON module you  can create records in JSON format and use the RediSearch to query them.



Let's go create our API!



##### Project Setup  

Create a project folder ``redis-book-libray`` (you can name your project differently) and CD into the project folder.
`$ mkdir redis-book-libray`

`$ cd redis-book-libray` 

`$ yarn init -y`  (You can use NPM)

`$ yarn add express redis-om nodemon `


In your project root folder, create a `src`  folder that will hold most of your program logic. I like to separate concerns for code clarity, easy debugging and reusability. Let's set up our database connection.  Create a `connection.js`  file inside your `src` folder. On the `client.open()` method paste your database credentials there. You can get your database details from the configuration tab after logging.


```js
import { createClient } from 'redis';
import { Client } from 'redis-om';

// Database connection
const client = new Client()
// E.g URL = 'redis://default:WyfL..WH...AtUS3...jW...nf@redis-1...1.c73.us-...t-1-2.ec2.c..d.redislabs.com:1...1'
const DBConnection = await client.open('redis://username:password@Public-endpoint:port');

export default DBConnection;

```

##### Database Credentials 
After registration, on your side bar click on `Databases`   go to your `Configuration` tab, under `General` you will see your  public endpoint which is your host and the digits after the colon is your port number, scroll down to security you will see your username and password. If you are using the free subscription your username is **default**.  

Inside your `src`  folder, create an `app.js` file that will serve as the gateway to your application. Don't pay attention to the imported route function for now. That will be sorted out later.

```js
import express from 'express';
import routes from './routes.js';

const app = express()


app.use(express.json());


const PORT = process.env.PORT || 3000

app.use('/api/v1', routes);

app.listen(PORT, async () => {
    console.log(`app is running on port ${PORT}`)
})
```

Go to your `package.json` file and set up your scripts.

```js
{
  "name": "redis-book-libray",
  "version": "1.0.0",
  "main": "./src/app.js",
  "license": "MIT",
  "scripts": {
    "start": "nodemon ./src/app.js"
  },
  "type": "module",
  "dependencies": {
    "express": "^4.18.1",
    "nodemon": "^2.0.19",
    "redis-om": "^0.3.6"
  },
  "devDependencies": {
    "nodemon": "^2.0.19"
  }
}
```

Go to your terminal or CMD, cd into your project and run `yarn start`  or `npm start`.

The Next step is to define the **Entity**,  **Schema** and **Repository**.

An **Entity** is a class for wrapping the objects that will be stored in the database. The Book Entity will extend to Redis OM Entity that will hold your data.

**Schema** is what we use to describe how the data will look. It defines the field and their types on the entity.

**Repository** is the interface that gives you access to create, read, update and delete methods that you can use to manipulate your records from the **Entity** class.

Inside the `src`  folder create an `BookEntity.js` file that contains your Book Entity and Repository.

```js
import { Entity, Schema } from 'redis-om';
import DBConnection  from './connection.js'

export class Book extends Entity {}

const BookSchema = new Schema(Book, {
    title: { type: 'string' },
    author: { type: 'string' },
    pages: { type: 'number' },
    publisher: { type: 'string' },
    publishedDate: { type: 'date' },
},{
    dataStructure: 'JSON'
});

export const BookRepository = DBConnection.fetchRepository(BookSchema)
await BookRepository.createIndex()
```

Lets create our Controller and Routes file. Inside the `src` folder create a `BookController.js` file. This file will be a class that will contain your CRUD methods.

```js
import { BookRepository } from './BookEntity.js';

export default class BookController {
    
    // store book
    static store = async (req, res, next) => {
        try {
            const book = await BookRepository.createAndSave(req.body);
    
            return res.send({
                status: "successful",
                data: book
            }, 201)
        } catch (error) {
            return next(error)
        }
    }

    // fetch specified book
    static getBook = async (req, res, next) => {
        try {
            const book = await BookRepository.fetch(req.params.id)
            return res.send({
                status: "successful",
                data: book
            })
        }catch (error) {
            return next(error)
        }
    }

    // update book
    static update = async (req, res, next) => {
        try {
            const book = await BookRepository.fetch(req.params.id);
            book.title = req.body.title;
            book.author = req.body.author;
            book.pages = req.body.pages;
            book.publisher = req.body.publisher;
            book.publishedDate = req.body.publishedDate;
            await BookRepository.save(book);

            return res.send({
                status: "successful",
                data: book
            })
        } catch (error) {
            return next(error)
        }
    }

    // delete book
    static delete = async (req, res, next) => {
        try {
            const id = req.params.id
            const result = await BookRepository.remove(id);
    
            return res.send({
                status: "successful",
            }, 200)
        } catch (error) {
            return next(error)
        } 
    }
}
```

Let's set up our router with the necessary endpoints. Inside the `src` folder create a `routes.js` file. Remember your route file has been imported on the `app.js` file and it is bind to your **Express** app.

```js
import express from 'express';
import BookController from './BookController.js';
import BookSearchController from './BookSearchController.js';

const router = express.Router();

router.post('/create', BookController.store)
router.get('/:id/book', BookController.getBook)
router.post('/:id/book', BookController.update)
router.delete('/:id/book', BookController.delete)

export default router;
```

Go to your terminal on the root folder of your project and enter this command `yarn start` or `npm start` to start your app. Open your Postman (or whatever tool you use to test or consume RESTful APIs) and test your endpoint.

![image](https://drive.google.com/uc?export=view&id=1j3xUZJr3yeidyR7-nDkq2cwwtmSP4p6v)



​                                                 

#### RediSearch

Is time to carry out some search on your Book records including full-text search. The Search class contains five methods. 

```javascript
import { BookRepository } from './BookEntity.js';

export default class BookSearchController {
    // find all book records
    static findAll = async (req, res) => {
        const result = await BookRepository.search().return.all()
        return res.json(result)
    }

    // find all albums where the artist is 'Charles Dickens'
    static findByAuthor = async (req, res) => {
        const result = await BookRepository.search().where('author').equals('Charles Dickens').return.all()
        return res.json(result);
    }

    // find all books where publishedDate year is equal to 2022
    static findByYear = async (req, res) => {
        const result = await BookRepository.search().where('publishedDate').eq(2022).return.all()
        return res.json(result)
    }

    // find first record
    static findFirstRecord = async (req, res) => {
        const result  = await BookRepository.search().return.first()
        return res.json(result)
    }

    // count all book records
    static countAll = async (req, res) => {
        const result = await BookRepository.search().return.count()
        return res.json(result)
    }
}
```

Go to your `routes.js` file and bind your search methods to your Express router.

```js
import express, { Router } from 'express';
import BookController from './BookController.js';
import BookSearchController from './BookSearchController.js';

const router = express.Router();

router.post('/create', BookController.store)
router.get('/:id/book', BookController.getBook)
router.post('/:id/book', BookController.update)
router.delete('/:id/book', BookController.delete)

// search routes
router.get('/search/count', BookSearchController.countAll)
router.get('/search/all', BookSearchController.findAll)
router.get('/search/:author', BookSearchController.findByAuthor)
router.get('/search/:year', BookSearchController.findByYear)
router.get('/search', BookSearchController.findFirstRecord)


export default router;
```



Your file structure should look like the one below if you followed my tutorial.

```
📦redis-book-libray
 ┣ 📂node_modules
 ┣ 📂src
 ┃ ┣ 📜BookController.js
 ┃ ┣ 📜BookEntity.js
 ┃ ┣ 📜BookSearchController.js
 ┃ ┣ 📜app.js
 ┃ ┣ 📜connection.js
 ┃ ┗ 📜routes.js
 ┣ 📜package.json
 ┗ 📜yarn.lock
```



##### Conclusion

You have learned how to use the Redis OM, NodeJs and Express framework to develop RESTful APIs



RESTful APIs using the Redis OM and NodeJs with Express framework. You can go ahead and create more Entities (E.g Publisher) to get acquainted with the Redis technologies. [GitHub](https://github.com/Tochine/digital-book-library-api-with-redis-om-nodejs) repository to the project.

***This post is in collaboration with [Redis](https://redis.io/)***



##### Related

*[Try Redis Cloud for free](https://redis.com/try-free/?utm_campaign=write_for_redis)*

*[Redis Developer Hub - tools, guides, and tutorials about Redis](https://redis.info/3LC4GqB)*

*[RedisInsight Desktop GUI](https://redis.io/docs/stack/insight/?utm_campaign=write_for_redis)* 



*[Watch this video on the benefits of Redis Cloud over other Redis providers](https://www.youtube.com/watch?v=vyxdC1qK4NE)* 

<video src="https://drive.google.com/uc?export=view&id=1GFqYQ2OROZ-aMrUS0mWwopunVgV-oD4J"></video>