A RESTful API is a method to expose data and perform CRUD operations on top of the HTTP protocol.
In this exercise we will be creating a web server using NodeJS and the ExpressJS framework. Data will be stored in MySQL and we will be using Sequelize to model the tables and relations.
In order to initialize a node app open a directory where you want to create the app and execute the following command in the terminal
npm init
You will be prompted to fill in the following details:
Name
Version
Description
Entry point
Test command
Git repository
Keywords
Author
License
Before completing this step you need to confirm the data is correct:
If everything went well a pagckage.json file is generated
TODO: check if the package.json exists
TODO: create a new file called server.js
ExpressJS is a lightweight, but powerful framework for building web applications or web services.
To include this dependency in your project run the following npm command
npm install express --save
Write the code in the server.js file
const express = require('express')
Next create a constant calledapp
const app = express()
Use the static files middleware to serve your webpage assets express.static
app.use('/', express.static('frontend'))
The first parameter is the path where you want the files to be served. The second parameter is the middleware configured with the directory where the files are located.
Configure the server to listen to 8080 port for HTTP.
app.listen(8080)
TODO: create a directory called frontend
TODO: add a new file called index.html
TODO: open the app in the browser (http://localhost:8080) - make sure to replace localhost with your IP if you work in the cloud
If you haven't done this already, follow the tutorial published here.
Login into the console and create a database called profile:
create database profile;
TODO: check if the database was created by executing show databases;
TODO: exit the console by typing exit
and pressing enter
Sequelize is an object oriented library that provides a high level mapping between the database and your code. In practice we call this pattern object-relational mapping (ORM). It allows us to represent tables from the database by creating models and relationships. On each model basic CRUD (Create, Read, Update, Delete) operations are exposed.
Sequelize is a wrapper on multiple database drivers. In our example we will use mysql2. Both the library and the drivers will be installed using npm.
npm install --save sequelize
npm install --save mysql2
Next edit the server.js file and create an instance of the Sequelize class
const Sequelize = require('sequelize')​const sequelize = new Sequelize('profile', 'root', '', {dialect: "mysql",host: "localhost"})
Notice the difference between sequelize
as an object and Sequelize
as a class.
The first parameter of the constructor is the database name, the second parameter is the username and the third is the password. Further options are passed as an object in the fourth parameter.
In order to perform the database connection we call the authenticate() method.
As many Sequelize methods, the authentication will be asynchronous, thus it will return a promise. Promise
. When the promise is fulfilled the function passed as a parameter on the then() method is called. If the promise gets rejected the function on the catch() method will be called.
sequelize.authenticate().then(() => {console.log("Connected to database")}).catch((err) => {console.log(err)console.log("Unable to connect to database")})
TODO: run node server.js
TODO: check the console for the message: Connected to database
The fist parameter is the name of the table. As a convention is preferred to define the tables using English language and use the plural version. The second parameter is an object that describes the structure of the table as key value pairs.
const Messages = sequelize.define('messages', {subject: Sequelize.STRING,name: Sequelize.STRING,message: Sequelize.TEXT})
Extended documentation is here - http://docs.sequelizejs.com/manual/tutorial/models-definition.html​
Supported data type - http://docs.sequelizejs.com/manual/tutorial/models-definition.html#data-types​
Using sync() all the models will be created in your database
Note that by adding {force: true}
existent tables will be recreated from scratch
To create the tables we are exposing a GET /createdb endpoint
app.get('/createdb', (request, response) => {sequelize.sync({force:true}).then(() => {response.status(200).send('tables created')}).catch((err) => {console.log(err)response.status(200).send('could not create tables')})})
TODO: open the browser and navigate to http://localhost:8080/createdb
TODO: login to the mysql console type use profile
and show tables;
to check if the tables were created
Now that we have the model let's implement the Create, Read, Update and Delete operations.
We consider the following endpoint
POST /messages
The client will perform a HTTP request containing data in json
or urlencoded
. To parse the data we need to add two middleware functions. The endpoint is defined using app.post
app.use(express.json())app.use(express.urlencoded())​//definire endpoint POST /messagesapp.post('/messages', (request, response) => {Messages.create(request.body).then((result) => {response.status(201).json(result)}).catch((err) => {response.status(500).send("resource not created")})})
create ---> INSERT INTO messages (`subject`, `name`, `message`) VALUES ('test','test','test')
.
Choose POST
Type the URL of the resource
Choose raw a body type
Choose application/json content type
Press Send
Considering the following endpoints. The first one will retrieve all the entries in the table. The second will retrieved one entry identified by the ID 1.
GET /messages
GET /messages/1
Details on data queries: http://docs.sequelizejs.com/manual/tutorial/querying.html​
app.get('/messages', (request, response) => {Messages.findAll().then((results) => {response.status(200).json(results)})})​app.get('/messages/:id', (request, response) => {Messages.findByPk(request.params.id).then((result) => {if(result) {response.status(200).json(result)} else {response.status(404).send('resource not found')}}).catch((err) => {console.log(err)response.status(500).send('database error')})})
TODO: test the endpoint in POSTMAN
Considering the following endpoint
PUT /messages/1
First, the resource is retrieved by ID. If the resource was not found the server's response is 404 NOT FOUND
If the resource was fount we call the update()
method with the payload sent by the client in the body.
app.put('/messages/:id', (request, response) => {Messages.findByPk(request.params.id).then((message) => {if(message) {message.update(request.body).then((result) => {response.status(201).json(result)}).catch((err) => {console.log(err)response.status(500).send('database error')})} else {response.status(404).send('resource not found')}}).catch((err) => {console.log(err)response.status(500).send('database error')})})
TODO: test the endpoint in POSTMAN
Considering the following endpoint
DELETE /messages/1
First, the resources is retrieved by id. If the resource was found we are calling the destroy method to send the delete instruction. This will return a Promise that needs to be treated accordingly. If the delete was successful the server's response is 204 NO CONTENT
app.delete('/messages/:id', (request, response) => {Messages.findByPk(request.params.id).then((message) => {if(message) {message.destroy().then((result) => {response.status(204).send()}).catch((err) => {console.log(err)response.status(500).send('database error')})} else {response.status(404).send('resource not found')}}).catch((err) => {console.log(err)response.status(500).send('database error')})})
TODO: test the endpoint in POSTMAN
const express = require('express')const Sequelize = require('sequelize')​const sequelize = new Sequelize('profile', 'root', '', {dialect: "mysql",host: "localhost"})​sequelize.authenticate().then(() => {console.log("Connected to database")}).catch((err) => {console.log(err)console.log("Unable to connect to database")})​const Messages = sequelize.define('messages', {subject: Sequelize.STRING,name: Sequelize.STRING,message: Sequelize.TEXT})​const app = express()app.use('/', express.static('frontend'))​app.use(express.json())app.use(express.urlencoded())​app.get('/createdb', (request, response) => {sequelize.sync({force:true}).then(() => {response.status(200).send('tables created')}).catch((err) => {console.log(err)response.status(200).send('could not create tables')})})​//definire endpoint POST /messagesapp.post('/messages', (request, response) => {Messages.create(request.body).then((result) => {response.status(201).json(result)}).catch((err) => {response.status(500).send("resource not created")})})​​app.get('/messages', (request, response) => {Messages.findAll().then((results) => {response.status(200).json(results)})})​app.get('/messages/:id', (request, response) => {Messages.findByPk(request.params.id).then((result) => {if(result) {response.status(200).json(result)} else {response.status(404).send('resource not found')}}).catch((err) => {console.log(err)response.status(500).send('database error')})})​app.put('/messages/:id', (request, response) => {Messages.findByPk(request.params.id).then((message) => {if(message) {message.update(request.body).then((result) => {response.status(201).json(result)}).catch((err) => {console.log(err)response.status(500).send('database error')})} else {response.status(404).send('resource not found')}}).catch((err) => {console.log(err)response.status(500).send('database error')})})​​app.delete('/messages/:id', (request, response) => {Messages.findByPk(request.params.id).then((message) => {if(message) {message.destroy().then((result) => {response.status(204).send()}).catch((err) => {console.log(err)response.status(500).send('database error')})} else {response.status(404).send('resource not found')}}).catch((err) => {console.log(err)response.status(500).send('database error')})})​​app.listen(8080)
const express = require('express')const Sequelize = require('sequelize')​const sequelize = new Sequelize('profile', 'root', '', {dialect: "mysql",host: "localhost"})​sequelize.authenticate().then(() => {console.log("Connected to database")}).catch((err) => {console.log(err)console.log("Unable to connect to database")})​const Messages = sequelize.define('messages', {subject: Sequelize.STRING,name: Sequelize.STRING,message: Sequelize.TEXT})​const app = express()app.use('/', express.static('frontend'))​app.use(express.json())app.use(express.urlencoded())​app.get('/createdb', async (request, response) => {try {await sequelize.sync({force:true})response.status(200).send('tables created')} catch(err) {console.log(err)response.status(200).send('could not create tables')}})​//definire endpoint POST /messagesapp.post('/messages', async (request, response) => {try {let result = await Messages.create(request.body)response.status(201).json(result)} catch(err) {console.log(err)response.status(500).send("resource not created")}})​​app.get('/messages', async (request, response) => {try {let results = await Messages.findAll()response.status(201).json(results)} catch(err) {console.log(err)response.status(500).send("server error")}})​app.get('/messages/:id', async (request, response) => {try {let result = await Messages.findByPk(request.params.id)if(result) {response.status(200).json(result)} else {response.status(404).send('resource not found')}} catch(err) {console.log(err)response.status(500).send('database error')}})​app.put('/messages/:id', async (request, response) => {try {let message = await Messages.findByPk(request.params.id)if(message) {let result = await message.update(request.body)response.status(201).json(result)} else {response.status(404).send('resource not found')}} catch(err) {console.log(err)response.status(500).send('database error')}})​​app.delete('/messages/:id', async (request, response) => {try {let message = await Messages.findByPk(request.params.id)if(message) {await message.destroy()response.status(204).send()} else {response.status(404).send('resource not found')}} catch(err) {console.log(err)response.status(500).send('database error')}})​​app.listen(8080)
Get more in depth knowledge by reading this articles