{"id":55,"date":"2022-10-04T11:43:19","date_gmt":"2022-10-04T10:43:19","guid":{"rendered":"https:\/\/chigisoft.com\/blog\/?p=55"},"modified":"2023-07-01T18:14:05","modified_gmt":"2023-07-01T17:14:05","slug":"redis-om-developer-experience-using-node-js","status":"publish","type":"post","link":"https:\/\/chigisoft.com\/blog\/redis-om-developer-experience-using-node-js\/","title":{"rendered":"Redis OM: Developer Experience using Node.Js"},"content":{"rendered":"\n<p>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! &#8211; <strong>Raja Rao, <em>(VP of Growth Marketing at Redis)<\/em>.<\/strong><\/p>\n\n\n\n<p>I couldn&#8217;t agree more with <strong>Raja<\/strong>. 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 where I threw some light on the gains of using Redis and Redis Cloud.<\/p>\n\n\n\n<h5 id=\"redis-om\" class=\"wp-block-heading\"><br>Redis OM<\/h5>\n\n\n\n<p>Redis OM is the magic stick developers can use to create data models on our applications and map them 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), get a better experience while using Redis on our application.<\/p>\n\n\n\n<h5 id=\"goal\" class=\"wp-block-heading\">Goal<\/h5>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>Prerequisite<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Node Engine<\/li>\n\n\n\n<li>Yarn or NPM installer<\/li>\n\n\n\n<li>IDE (E.g: Visual Studio Code)<\/li>\n<\/ul>\n\n\n\n<h5 id=\"setup-redis-cloud-account\" class=\"wp-block-heading\">Setup Redis Cloud Account<\/h5>\n\n\n\n<p>You can use this link <a href=\"https:\/\/redis.com\/try-free\/?utm_campaign=write_for_redis\" target=\"_blank\" rel=\"noopener\">Redis Cloud<\/a> to create a free account. After registration click on the <mark class=\"has-inline-color has-vivid-red-color\"><code>New subscriptio<\/code>n<\/mark> button to set up a plan. If you&#8217;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 another vendor you&#8217;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.<\/p>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>Let&#8217;s go create our API!<\/p>\n\n\n\n<h5 id=\"project-setup\" class=\"wp-block-heading\">Project Setup<\/h5>\n\n\n\n<p>Create a project folder <mark class=\"has-inline-color has-vivid-red-color\">redis-book-libray<\/mark> (you can name your project differently) and CD into the project folder. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code>$ mkdir redis-book-libray<\/code><code>$ cd redis-book-libray<\/code>$ yarn init -y (You can use NPM)\n$ yarn add express redis-om nodemon<\/code><\/pre>\n\n\n\n<p>In your project root folder, create a <code>src<\/code> folder that will hold most of your program logic. I like to separate concerns for code clarity, easy debugging, and reusability. Let&#8217;s set up our database connection. Create a <code>connection.js<\/code> file inside your <code>src<\/code> folder. On the <code>client.open()<\/code> method paste your database credentials there. You can get your database details from the configuration tab after logging<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { createClient } from 'redis';\nimport { Client } from 'redis-om';\n\n\/\/ Database connection\nconst client = new Client()\n\/\/ 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'\nconst DBConnection = await client.open('redis:\/\/username:password@Public-endpoint:port');\n\nexport default DBConnection;<\/code><\/pre>\n\n\n\n<h5 id=\"database-credentials\" class=\"wp-block-heading\">Database Credentials<\/h5>\n\n\n\n<p>After registration, on your side bar click on <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\"><code>Databases<\/code><\/mark> go to your <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Configuration<\/mark> tab, under <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">General<\/mark> 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 <strong>default<\/strong>.<\/p>\n\n\n\n<p>Inside your <code><mark class=\"has-inline-color has-vivid-red-color\">src<\/mark><\/code> folder, create an <code><mark class=\"has-inline-color has-vivid-red-color\">app.js<\/mark><\/code> file that will serve as the gateway to your application. Ignore the imported route function for now. That will be sorted out later.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import express from 'express';\nimport routes from '.\/routes.js';\n\nconst app = express()\n\n\napp.use(express.json());\n\n\nconst PORT = process.env.PORT || 3000\n\napp.use('\/api\/v1', routes);\n\napp.listen(PORT, async () =&gt; {\n    console.log(`app is running on port ${PORT}`)\n})<\/code><\/pre>\n\n\n\n<p>Go to your <em><mark class=\"has-inline-color has-vivid-red-color\">package.json<\/mark><\/em> file and set up your scripts.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"name\": \"redis-book-libray\",\n  \"version\": \"1.0.0\",\n  \"main\": \".\/src\/app.js\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"start\": \"nodemon .\/src\/app.js\"\n  },\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"express\": \"^4.18.1\",\n    \"nodemon\": \"^2.0.19\",\n    \"redis-om\": \"^0.3.6\"\n  },\n  \"devDependencies\": {\n    \"nodemon\": \"^2.0.19\"\n  }\n}<\/code><\/pre>\n\n\n\n<p>Go to your terminal or CMD, CD (change directory) into your project and run <code>yarn start<\/code> or <code>npm start<\/code>.<\/p>\n\n\n\n<p>The Next step is to define the <strong>Entity<\/strong>, <strong>Schema<\/strong> and <strong>Repository<\/strong>.<\/p>\n\n\n\n<p>An <strong>Entity<\/strong> is a class for wrapping the objects that will be stored in the database. The Book Entity will extend to Redis OM Entity which will hold your data.<\/p>\n\n\n\n<p><strong>Schema<\/strong> is what we use to describe how the data will look. It defines the field and its types on the entity.<\/p>\n\n\n\n<p><strong>Repository<\/strong> is the interface that gives you access to create, read, update and delete methods that you can use to manipulate your records from the <strong>Entity<\/strong> class.<\/p>\n\n\n\n<p>Inside the <code><mark class=\"has-inline-color has-vivid-red-color\">src<\/mark><\/code> folder create a <code><mark class=\"has-inline-color has-vivid-red-color\">BookEntity.js<\/mark><\/code> file that contains your Book Entity and Repository.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { Entity, Schema } from 'redis-om';\nimport DBConnection  from '.\/connection.js'\n\nexport class Book extends Entity {}\n\nconst BookSchema = new Schema(Book, {\n    title: { type: 'string' },\n    author: { type: 'string' },\n    pages: { type: 'number' },\n    publisher: { type: 'string' },\n    publishedDate: { type: 'date' },\n},{\n    dataStructure: 'JSON'\n});\n\nexport const BookRepository = DBConnection.fetchRepository(BookSchema)\nawait BookRepository.createIndex()<\/code><\/pre>\n\n\n\n<p>Let&#8217;s create our Controller and Routes file. Inside the <code><mark class=\"has-inline-color has-vivid-red-color\">src<\/mark><\/code> folder create a <code><mark class=\"has-inline-color has-vivid-red-color\">BookController.js<\/mark><\/code> file. This file will be a class that will contain your CRUD methods.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { BookRepository } from '.\/BookEntity.js';\n\nexport default class BookController {\n    \n    \/\/ store book\n    static store = async (req, res, next) =&gt; {\n        try {\n            const book = await BookRepository.createAndSave(req.body);\n    \n            return res.send({\n                status: \"successful\",\n                data: book\n            }, 201)\n        } catch (error) {\n            return next(error)\n        }\n    }\n\n    \/\/ fetch specified book\n    static getBook = async (req, res, next) =&gt; {\n        try {\n            const book = await BookRepository.fetch(req.params.id)\n            return res.send({\n                status: \"successful\",\n                data: book\n            })\n        }catch (error) {\n            return next(error)\n        }\n    }\n\n    \/\/ update book\n    static update = async (req, res, next) =&gt; {\n        try {\n            const book = await BookRepository.fetch(req.params.id);\n            book.title = req.body.title;\n            book.author = req.body.author;\n            book.pages = req.body.pages;\n            book.publisher = req.body.publisher;\n            book.publishedDate = req.body.publishedDate;\n            await BookRepository.save(book);\n\n            return res.send({\n                status: \"successful\",\n                data: book\n            })\n        } catch (error) {\n            return next(error)\n        }\n    }\n\n    \/\/ delete book\n    static delete = async (req, res, next) =&gt; {\n        try {\n            const id = req.params.id\n            const result = await BookRepository.remove(id);\n    \n            return res.send({\n                status: \"successful\",\n            }, 200)\n        } catch (error) {\n            return next(error)\n        } \n    }\n}<\/code><\/pre>\n\n\n\n<p>Let&#8217;s set up our router with the necessary endpoints. Inside the <code><mark class=\"has-inline-color has-vivid-red-color\">src<\/mark><\/code> folder create a <code><mark class=\"has-inline-color has-vivid-red-color\">routes.js<\/mark><\/code> file. Remember your route file has been imported on the <code>app.js<\/code> file and it is binding to your <strong>Express<\/strong> app.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import express from 'express';\nimport BookController from '.\/BookController.js';\nimport BookSearchController from '.\/BookSearchController.js';\n\nconst router = express.Router();\n\nrouter.post('\/create', BookController.store)\nrouter.get('\/:id\/book', BookController.getBook)\nrouter.post('\/:id\/book', BookController.update)\nrouter.delete('\/:id\/book', BookController.delete)\n\nexport default router;<\/code><\/pre>\n\n\n\n<p>Go to your terminal on the root folder of your project and enter this command <code>yarn start<\/code> or <code>npm start<\/code> to start your app. Open your Postman (or whatever tool you use to test or consume RESTful APIs) and test your endpoint.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/drive.google.com\/uc?export=view&amp;id=1j3xUZJr3yeidyR7-nDkq2cwwtmSP4p6v\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Rest API<\/figcaption><\/figure>\n\n\n\n<h4 id=\"redisearch\" class=\"wp-block-heading\">RediSearch<\/h4>\n\n\n\n<p>Is time to carry out some searches on your Book records including a full-text search. The Search class contains five methods.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { BookRepository } from '.\/BookEntity.js';\n\nexport default class BookSearchController {\n    \/\/ find all book records\n    static findAll = async (req, res) =&gt; {\n        const result = await BookRepository.search().return.all()\n        return res.json(result)\n    }\n\n    \/\/ find all albums where the artist is 'Charles Dickens'\n    static findByAuthor = async (req, res) =&gt; {\n        const result = await BookRepository.search().where('author').equals('Charles Dickens').return.all()\n        return res.json(result);\n    }\n\n    \/\/ find all books where publishedDate year is equal to 2022\n    static findByYear = async (req, res) =&gt; {\n        const result = await BookRepository.search().where('publishedDate').eq(2022).return.all()\n        return res.json(result)\n    }\n\n    \/\/ find first record\n    static findFirstRecord = async (req, res) =&gt; {\n        const result  = await BookRepository.search().return.first()\n        return res.json(result)\n    }\n\n    \/\/ count all book records\n    static countAll = async (req, res) =&gt; {\n        const result = await BookRepository.search().return.count()\n        return res.json(result)\n    }\n}<\/code><\/pre>\n\n\n\n<p>Go to your <code><mark class=\"has-inline-color has-vivid-red-color\">routes.js<\/mark><\/code> file and bind your search methods to your Express router.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import express, { Router } from 'express';\nimport BookController from '.\/BookController.js';\nimport BookSearchController from '.\/BookSearchController.js';\n\nconst router = express.Router();\n\nrouter.post('\/create', BookController.store)\nrouter.get('\/:id\/book', BookController.getBook)\nrouter.post('\/:id\/book', BookController.update)\nrouter.delete('\/:id\/book', BookController.delete)\n\n\/\/ search routes\nrouter.get('\/search\/count', BookSearchController.countAll)\nrouter.get('\/search\/all', BookSearchController.findAll)\nrouter.get('\/search\/:author', BookSearchController.findByAuthor)\nrouter.get('\/search\/:year', BookSearchController.findByYear)\nrouter.get('\/search', BookSearchController.findFirstRecord)\n\n\nexport default router;<\/code><\/pre>\n\n\n\n<p>Your file structure should look like the one below if you followed my tutorial.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\ud83d\udce6redis-book-libray\n \u2523 \ud83d\udcc2node_modules\n \u2523 \ud83d\udcc2src\n \u2503 \u2523 \ud83d\udcdcBookController.js\n \u2503 \u2523 \ud83d\udcdcBookEntity.js\n \u2503 \u2523 \ud83d\udcdcBookSearchController.js\n \u2503 \u2523 \ud83d\udcdcapp.js\n \u2503 \u2523 \ud83d\udcdcconnection.js\n \u2503 \u2517 \ud83d\udcdcroutes.js\n \u2523 \ud83d\udcdcpackage.json\n \u2517 \ud83d\udcdcyarn.lock<\/code><\/pre>\n\n\n\n<h5 id=\"conclusion\" class=\"wp-block-heading\">Conclusion<\/h5>\n\n\n\n<p>You have learned how to use the Redis OM, NodeJs and Express framework to develop RESTful APIs. You can go ahead and create more Entities (E.g Publisher) to get acquainted with the Redis technologies. <a href=\"https:\/\/github.com\/Tochine\/digital-book-library-api-with-redis-om-nodejs\" target=\"_blank\" rel=\"noopener\">GitHub<\/a> repository to the project.<\/p>\n\n\n\n<p><em><strong>This post is in collaboration with <a href=\"https:\/\/redis.io\/\" target=\"_blank\" rel=\"noopener\">Redis<\/a><\/strong><\/em><\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/learn.chigisoft.com\/\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"675\" data-id=\"469\" src=\"https:\/\/chigisoft.com\/blog\/wp-content\/uploads\/2023\/07\/Learn-product-design-with-Chigisoft-4-edited.png\" alt=\"\" class=\"wp-image-469\" srcset=\"https:\/\/chigisoft.com\/blog\/wp-content\/uploads\/2023\/07\/Learn-product-design-with-Chigisoft-4-edited.png 1200w, https:\/\/chigisoft.com\/blog\/wp-content\/uploads\/2023\/07\/Learn-product-design-with-Chigisoft-4-edited-300x169.png 300w, https:\/\/chigisoft.com\/blog\/wp-content\/uploads\/2023\/07\/Learn-product-design-with-Chigisoft-4-edited-1024x576.png 1024w, https:\/\/chigisoft.com\/blog\/wp-content\/uploads\/2023\/07\/Learn-product-design-with-Chigisoft-4-edited-768x432.png 768w, https:\/\/chigisoft.com\/blog\/wp-content\/uploads\/2023\/07\/Learn-product-design-with-Chigisoft-4-edited-390x219.png 390w, https:\/\/chigisoft.com\/blog\/wp-content\/uploads\/2023\/07\/Learn-product-design-with-Chigisoft-4-edited-820x461.png 820w, https:\/\/chigisoft.com\/blog\/wp-content\/uploads\/2023\/07\/Learn-product-design-with-Chigisoft-4-edited-1180x664.png 1180w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure>\n<\/figure>\n\n\n\n<h5 id=\"related\" class=\"wp-block-heading\">Related<\/h5>\n\n\n\n<p><strong><a href=\"https:\/\/redis.com\/try-free\/?utm_campaign=write_for_redis\" target=\"_blank\" rel=\"noopener\">Try Redis Cloud for free<\/a><\/strong><\/p>\n\n\n\n<p><strong><a href=\"https:\/\/redis.info\/3LC4GqB\" target=\"_blank\" rel=\"noopener\">Redis Developer Hub &#8211; tools, guides, and tutorials about Redis<\/a><\/strong><\/p>\n\n\n\n<p><strong><a href=\"https:\/\/redis.info\/3wMR7PR\" target=\"_blank\" rel=\"noopener\">RedisInsight Desktop GUI<\/a><\/strong><\/p>\n\n\n\n<p><strong><a href=\"https:\/\/redis.info\/3Ga9YII\" target=\"_blank\" rel=\"noopener\">Watch this video on the benefits of Redis Cloud over other Redis providers<\/a><\/strong><\/p>\n\n\n\n<p>Also check out \u2014 <a href=\"https:\/\/chigisoft.com\/blog\/redis-redisinsight-installation-on-ubuntu-20-04-connection-to-redis-stack-server-docker-container\/\" data-type=\"post\" data-id=\"20\">Redis Installation<\/a><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"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!&hellip;\n","protected":false},"author":3,"featured_media":101,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,14],"tags":[15,16,9,18,17],"class_list":{"0":"post-55","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-tech","8":"category-devops","9":"tag-nodejs","10":"tag-programming","11":"tag-redis","12":"tag-softwaredevelopment","13":"tag-tutorial"},"_links":{"self":[{"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/posts\/55","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/comments?post=55"}],"version-history":[{"count":9,"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/posts\/55\/revisions"}],"predecessor-version":[{"id":470,"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/posts\/55\/revisions\/470"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/media\/101"}],"wp:attachment":[{"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/media?parent=55"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/categories?post=55"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/chigisoft.com\/blog\/wp-json\/wp\/v2\/tags?post=55"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}