Node, Express and PostgreSQL using Sequelize (In Ubuntu 18.04.3 LTS)
A warm welcome to my understanding and learnings on Node, Express and PostgreSQL using Sequelize. My learning is from a blog post and link to that is — https://scotch.io/tutorials/getting-started-with-node-express-and-postgres-using-sequelize
Though it is already posted, the reason for writing about it here is due to my learning and Sequelize version upgrade from v4 to v5, where I installed Sequelize v5 and followed Sequelize v4 blog post. Minor changes are done when upgrading from Sequelize v4 to Sequelize v5. Okay let’s jump into the Node with Sequelize right away
Topics Covered,
- Node (JS Runtime for Server Side)
- Express (Web Framework)
- PostgreSQL (Database)
- Sequelize (A database Object Relational Mapping that will interface with PostgreSQL)
- Postman (API testing tool)
Project Setup,
- Create a folder named postgres-express-react-node-tutorial and subdirectories bin and server
- In terminal type as mkdir -p node-sequelize/{bin,server}
- Navigate to root folder by typing in terminal as cd node-sequelize
- Initialize a NodeJS application by typing in terminal as npm init -y (-y can be omitted to have control over package.json file’s configuration)
- Now the root directory will look like this,
Express Setup,
- Now we will install Express (A web framework and its dependencies)
- Type in terminal as npm install — save express body-parser morgan
- This will install Express, body-parser, morgan
- body-parser extract the entire body portion of an incoming request stream and exposes it on req. body . … This body-parser module parses the JSON, buffer, string and URL encoded data submitted using HTTP POST request
- Morgan is a HTTP request logger middleware for Node.js. It simplifies the process of logging requests to your application. You might think of Morgan as a helper that generates request logs
- Now lets create app.js file by typing in terminal as touch app.js
- Following content goes into the app.js file
- In the app.js file
- We are requiring the installed dependencies in our project — Express, Morgan, Body-parser
- Setup the express app using by making it as a function express() and assign to variable app
- Now make the express app to use the morgan logger by app.use(logger(‘dev’))
- Parse the incoming request data
- Then make the express app to use the body-parser by
- app.use(bodyParser.json())
- app.use(bodyParser.urlencoded({extended: false}))
- Then we will set a default route to the application as mentioned in the image
- Now we need to create the server for our app.js file
- Go to bin folder and create a www file by typing in terminal as touch www
- Following content goes into www file
- Now we will install nodemon a package that automatically reloads the page whenever a change in code is saved
- Type as npm i -D nodemon (-D saves the developer dependencies in our package.json file)
- Lets create script in package.json file to start our application. Following content goes into package.json file
- Now in command line enter npm start to start the application
- Go to the http://localhost:3000 in browser to view the application running
Sequelize Setup,
- First we will install Sequelize CLI package by typing in terminal as npm install -g sequelize-cli
- Next, we need to configure Sequelize for our project. For that, we will create a .sequelizerc file in our project’s root folder. In this file, we are going to be specifying the paths to files required by Sequelize. Following content needs to be pasted in .sequelizerc file,
- config.json file contains our application’s configuration such as database authentication
- models folder holds the application model
- seeders folder holds the seed data but we are not going to use it in this application
- migrations folder holds our application’s migration
- Lets install the Sequelize package with it’s dependencies by typing in terminal as npm install — save sequelize pg pg-hstore
- pg creates database connection
- pg-hstore is a module for serializing and deserializing JSON data into Postgres hstore format
- Now we will initialize sequelize by typing in terminal as sequelize init
- This will create the folders and files specified in .sequelizerc file
- Now the root directory will look like following image,
Installing PostgreSQL,
- Open terminal and type as sudo apt update
- Now type as sudo apt install postgresql postgresql-contrib
- Create a new user by typing in terminal by entering as su — postgres
- Then enter password of root user
- Enter as createuser — interactive — pwprompt
- Enter name of role as per your preference
- Enter password for the role
- Make it as Superuser
- Now create a database by typing as createdb -O user_1 todos_dev
- This will create a todos_dev database under the user_1 user
- We can see the list of databases present in postgres user by typing \l. It will also show the Users under whom the database is available in Owner column
Generating Models,
- We are going to have two models namely Todo and TodoItems
- Relationship between them are Todo can have many TodoItems whereas a TodoItem can belong to One Todo
- Type this command in terminal sequelize model:create — name Todo — attributes title:string
- This will create todo.js file in /server/models/ folder and migration file <date>-create-todo.js in /server/migrations folder (<date>-create-todo.js, date is the date the model is generated)
- Lets generate TodoItem model by typing in terminal as sequelize model:create — name TodoItem — attributes content:string,complete:boolean
- Define relationship between models, (Todo.hasMany…as:todoItems)
- allowNull: false — This will not allow us to submit a title without entering any input
- We also defined the relationship between Todo and TodoItems in the Todo.associate class method
- The as: ‘todoItems’ means that every time we query for a todo and include it’s todo items, they’ll be included under the key todoItems instead of TodoItems (Sequelize defaults to using the pluralized model name)
- Given below is the code For the TodoItems which has default value. It means that if we don’t provide a value, the database is going to take the provided default value
- Also the on delete means that it tells Postgres that if we delete a todo, it’s associated todo items should be deleted as well (cascade the delete action)
- Given below is the migration file for our models(todo.js & todoItem.js) which defines how we want our models to look like in the database. Below image we have refactored code to ES6
- When running these migrations up function will be executed. It will take care of creating the table and its associated columns for us
- If we need to rollback to previous version, the down function will be executed thus returning us the database to the previous state before we performed the migration (up function)
- Notice we define the relationship between our models in the create-todo-item.js migration file as well.
- The todoId field was not automatically generated and we’ve had to manually define it.
- Sequelize automatically generates the id, createdAt and updatedAt fields for you.
- In addition to that, any time a model is saved, the updatedAt field is automatically updated to reflect the new update time
- After the models and migrations are in place we are ready to send the models to the database by running the migrations. Run the following command in terminal to do so,
- sequelize db:migrate
- After the sequelize db:migrate CLI will show result similar to the image below,
Creating Controller and Routing,
- We will have todosController and todoItemsController. todosController will be responsible for creating, listing, updating and deleting todos. todoItemsController will be responsible for creating, updating and deleting todo items
- Create a new folder (controller) and a new file (todo.js) in server folder. Now it will be like this — server/controller/todo.js
- After that go to todo.js file and include the content as below image,
- The code mentioned above creates a new todo, if successful return it and if failure it will return the error
- req — It is the incoming request from the client
- res — It is the response against the request which we are giving to client
- Next we will create an index.js file in server/controller folder where we will be exporting our controllers from,
- Next, we need to add an API route that maps to this functionality. Create a routes folder inside the server folder.
- Inside the new routes folder, create an index.js file. We are going to place all our routes here.
- Following code goes into the index.js of routes folder whose path is server/router/
- The above code snippets will add two routes — /api & /api/todos
- /api — It is a welcome route
- When we call this, we are requesting our app to send back JSON object welcoming the user
- /api/todos — It is a request to create todo
- When we post a data we are telling our app to run todosController.create function which will take the request object, extract the posted data and create a todo from it
- Here we say todosController.create function is the POST route handler for the /api/todos endpoint
- Now we will tell our application that we have added the routes by adding the require in app.js file.
- Start the server by running npm start in terminal
- By using Postman we will do a POST request to create a new todo. Image is below,
Listing Todos,
- Lets add the following block of code after create method in server/controller/todo.js
- Here we are fetching all todos from our database and sending them back to the user as array in the response
- If any error is occured while fetching the todos from our database we are sending the error object
- Next, open up server/routes/index.js and create a new url that maps a todos GET request to the list method right below the POST route we’d added earlier,
- Let’s open Postman and do a GET request for the new url (route path — /api/todos)
Creating Todo Items,
- Create a todoitems.js file in server/controller folder so that we can add todo items in todo
- Following content goes into todoitems.js file,
- Here we are creating a todoitem and associating it with a particular todo by grabbing the id of that particular todo through req.params.todoId
- Following content goes into index.js file of server/controller folder,
- Here we are exporting the todoItems controller from this default export file
- We will setup the route for creating a new todoitem and see how the todoId is specified. Open the index.js file in server/routes/ folder,
- :todoId is made available to us by Express in request.params object as todoId and it is the same one we are accessing in our controller
- We also need to require todoItemsController in server/routes/index.js file
- Using Postman we will create todo items,
Listing todo-items inside todos,
- Now we are able to create todos and todoitem. Next we have to show the todoitems with respective todos so we need to modify todosController.list code which is in todo.js of server/controller/ folder.
- We require TodoItem model at top of todo.js file in server/controller folder
- Open Postman and make a get request to 127.0.0.1:3000/api/todos to view the todo and todoitems
Retrieving a Single Todo,
- In this section, we are going to get a single todo and its todoitems based on a todoId
- Add the following into todo.js file which is at server/controller/ folder,
- In the above code, we are finding the todo whose id matches the todoId which we get from req.params.todoId and along with that we are also including the todoItems of the matching todoId
- If the todo exists we are sending todo along with todoItems. If not sending a message as Todo Not Found.
- If we face any error while processing the single retrieve by id we send the error object
- Now we need to add a route in index.js which is present in server/routes/ folder
Try the Postman GET request to retrieve the single todo like we have done for others
Updating a Single Todo,
- Add the following code in todo.js file which is present in server/controller/ folder,
- We are finding the todo by todoId and updating it’s title. If no title is provided, it will default to title which it already had
- Lets add a route in index.js which is present in server/routes/ folder
- Open Postman and do a PUT request to 127.0.01:3000/2 with,
- key as title and its value as second todo
Deleting Todos,
- Add the following block of code in todo.js file which is in server/controller folder
- Above code is similar to update except that we are not including todoitems here.
- In our models we have specified as onDelete action as CASCADE which will delete the todoitems also
- Add the route in index.js file which is present in server/routes folder
- Trying the Postman DELETE request gives the result similar to following image,
Updating and Deleting Todo Items,
- Updating and Deleting Todo Items is similar to Updating and Deleting Todo
- Add the following code in todoitems.js file which is in server/controller folder
- We are finding the todoitem to either update or delete by two criteria which are mentioned below,
- id of todoitem from req.params.todoItemId
- id of todo from req.params.todoId
- We have the same approach as we update the todo title image when we are updating a todoItem
- This works for application which has very less fields. If we have more fields we would give the Sequelize model update function the data and then specify the fields it should update.
- Using this approach, we pass the whole update object we get from the req.body to the update function.
- Using ES6’s Object.keys function, we extract the keys from the update object and tell the TodoItem Sequelize model to only update the fields that are present in the update data object.
- If we have a field in our model that’s missing from the update object, the update operation will leave that field untouched.
- We will add two routes in index.js file which is in server/routes folder
- We also specify a method not allowed message if there is any other request on todo items
- Similar to other requests we can do the Postman request for UPDATE and DELETE todo item
Hope my post on Node, Express and Postgres using Sequelize gave you a good understanding. Thank you.