Skip to content

ExpreesJS Introduction#

What Is The ExpressJs?#

  • Express.js is a small framework that works on top of NodeJs web server functionality to simplify its APIs and add helpful new features. It makes it easier to organize your application’s functionality with middleware and routing. It adds helpful utilities to NodeJs HTTP objects and facilitates the rendering of dynamic HTTP objects.

  • More information (https://www.geeksforgeeks.org/introduction-to-express/?ref=lbp)

Why ExpressJs?#

  • Develops NodeJs web applications quickly and easily.
  • It’s simple to set up and personalise.
  • Allows you to define application routes using HTTP methods and URLs.
  • Includes a number of middleware modules that can be used to execute additional requests and responses activities.
  • Simple to interface with a variety of template engines, including Jade, Vash, and EJS.
  • Allows you to specify a middleware for handling errors.

  • More information (https://www.geeksforgeeks.org/introduction-to-express/?ref=lbp)

What Is The Middleware?#

  • Middleware in a NodeJs application refers to functions or modules that are executed in between the processing of an incoming request and the generation of a response. Middleware functions have access to the request and response objects, as well as the next function, which is used to pass control to the next middleware function in the chain.

  • Middleware functions can be used for a variety of purposes, such as logging, authentication, data validation, error handling, and more. They provide a way to modularize and organize the functionality of an application by breaking it into smaller, reusable components.

Install Express#

  • Now, let's create a project express-demo then run npm init to initialize package.json. After that let's install Express dependency to project by using the command below.
1
npm install express

Building First Web Server#

  • Okay, so let's create a file index.js and put the example code below.
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
//imports the Express module
const express = require('express');

//create an instance of the Express application by calling the `express()` function
const app = express();

//defines a route for the HTTP GET request to the root URL path
app.get('/', (req, res) => {
    res.send('Hello World');
});

//defines another route for the HTTP GET request to the path '/api/courses'
app.get('/api/courses', (req, res) => {
    res.send([1,2,3]);
});


//starts the Express server and makes it listen on port 3000
app.listen(3000, () => console.log('listening on port 3000...'))
  • Okay, as you can see, we will use require('express') to import express module and we will create an instance of the Express application by calling the express() function and this instance will be stored in the constant app.
  • Next, from the app we can use supported functions of express to create Apis and start the server which will listen on given port (Ex: 3000). If the server is started successfully then a log will be printed out.
  • Finally, let's start the express-demo and go to browser with 2 exported apis above, we can see the result as below.

 #zoom

 #zoom

Nodemon#

  • Nodemon is a utility tool for NodeJs developers that helps with development workflow by automatically restarting the NodeJs application whenever changes are made to the source code files. It stands for "Node Monitor," and its primary purpose is to save developers from manually stopping and restarting the NodeJs application each time they modify the code.
  • To install Nodemon, let's use the command below.
1
npm install -g nodemon
  • Now, instead of starting our node application by using node index.js. We will start it with nodemon.
1
nodemon index.js
1
2
3
4
5
6
7
duc@duc-MS-7E01:~/study/nodejs-backend/udemy/express-demo$ nodemon index.js 
[nodemon] 3.0.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node index.js`
listening on port 3000...
  • Now, if we make any change, then the server will be restarted automatically.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
duc@duc-MS-7E01:~/study/nodejs-backend/udemy/express-demo$ nodemon index.js 
[nodemon] 3.0.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node index.js`
listening on port 3000...
[nodemon] restarting due to changes...
[nodemon] starting `node index.js`
listening on port 3000...

Environment Variables#

  • As we can see, in our code the server port is hard code with port 3000, it is worked on our machine but maybe it will not work on other machine. We should not force every machine have to spend port 3000 for our application. So to fix it, we can use anenvironment variable.
  • An environment variable is basically a variable that is part of the environment in which a process runs. Its value is set outside this application.
  • To read a value from the environment with nodejs we can use the syntax below.
1
process.env.<Name Of Environment>
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const express = require('express');
const app = express();

app.get('/', (req, res) => {
    res.send('Hello World!!!');
});

app.get('/api/courses', (req, res) => {
    res.send([1,2,3]);
});

//Read the value of evnironment variable name PORT or 3000
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}...`))
  • As we can see, we will read the value from the environment variable name PORT and if this environment variable doesn't exist then we will get the value 3000 for the port.

  • Now, to set an environment variable name PORT to our machine we can use the command below.

1
export <ENV Name>=<ENV value>
1
export PORT=5000
1
2
3
4
5
6
7
8
duc@duc-MS-7E01:~/study/nodejs-backend/udemy/express-demo$ export PORT=5000
duc@duc-MS-7E01:~/study/nodejs-backend/udemy/express-demo$ nodemon index.js 
[nodemon] 3.0.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node index.js`
listening on port 5000...

Route Parameters#

  • In Apis, we usually see there are some parameters on the path. So firstly, to define a parameter in the api we can use syntax :<parameterName>
1
2
3
app.get('/api/courses/:<paramaterName>', (req, res) => {
    //......
});
1
2
3
app.get('/api/courses/:id', (req, res) => {
    //......
});
  • The example above show how do we define a parameter id in the api.
  • Next, to read a parameter value that we defined about, we will use req.params.<parameterName>.
1
2
3
app.get('/api/courses/:<parameterName>', (req, res) => {
    const id = req.params.<parameterName>;
});
  • Let's see the example below to read a parameter from the path with express.
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const express = require('express');
const app = express();

app.get('/', (req, res) => {
    res.send('Hello World!!!');
});

app.get('/api/courses', (req, res) => {
    res.send([1,2,3]);
});

app.get('/api/courses/:id', (req, res) => {
    res.send(req.params.id);
});

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}...`))

 #zoom

  • With multiple parameters we also have the same way to define and get. Let's see the example below.
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const express = require('express');
const app = express();

app.get('/', (req, res) => {
    res.send('Hello World!!!');
});

app.get('/api/courses', (req, res) => {
    res.send([1,2,3]);
});

app.get('/api/courses/:id', (req, res) => {
    res.send(req.params.id);
});

// multiple parameters in path and response is the params object
app.get('/api/courses/:year/:month', (req, res) => {
    res.send(req.params);
});

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}...`))

 #zoom

  • Okay, So we use route parameters for essential or required values whereas we use query string parameters for anything that is optional.
  • So if we are going to use query string instead of param to provide some additional data to back end services. We will use the req.query.<QueryName>.
1
2
3
4
app.get('/api/courses/:year/:month', (req, res) => {
    const name = req.query.<QueryName>;
    //...
});
1
2
3
4
app.get('/api/courses/:year/:month', (req, res) => {
    const sortBy = req.query.sortBy;
    //...
});
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const express = require('express');
const app = express();

app.get('/', (req, res) => {
    res.send('Hello World!!!');
});

app.get('/api/courses', (req, res) => {
    res.send([1,2,3]);
});

app.get('/api/courses/:id', (req, res) => {
    res.send(req.params.id);
});

app.get('/api/courses/:year/:month', (req, res) => {
    // res.send(req.params);
    res.send(req.query);
});


const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}...`))

 #zoom

Handling HTTP Get Requests#

  • Now, let's create some mock data and add them into the response for GET Apis that we created.
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const express = require('express');
const app = express();

const courses = [
    { id: 1, name: "course 1" },
    { id: 2, name: "course 2" },
    { id: 3, name: "course 3" }
]

app.get('/', (req, res) => {
    res.send('Hello World!!!');
});

// Return all the courses
app.get('/api/courses', (req, res) => {
    res.send(courses);
});


// Return the course by the input id
app.get('/api/courses/:id', (req, res) => {
    const course = courses.find(ci => ci.id === parseInt(req.params.id));
    if (!course) res.status(404).send('The course with the given Id was not found');
    res.send(course);
});

// app.get('/api/courses/:year/:month', (req, res) => {
//     // res.send(req.params);
//     res.send(req.query);
// });

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}...`))
  • In the /api/courses/:id we will find the item in the mock array following the id, if there the item is not there then an error 404 will be response with a message.

 #zoom

 #zoom

 #zoom

Handling HTTP Post Requests#

  • Now, let's create a POST /api/courses Api to create a Course object and push to the courses array as below.
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const express = require("express");
const app = express();

// use middleware `express.json` to parse request body to json
app.use(express.json());

const courses = [
  { id: 1, name: "course 1" },
  { id: 2, name: "course 2" },
  { id: 3, name: "course 3" },
];

app.get("/", (req, res) => {
  res.send("Hello World!!!");
});

app.get("/api/courses", (req, res) => {
  res.send(courses);
});

app.get("/api/courses/:id", (req, res) => {
  const course = courses.find((ci) => ci.id === parseInt(req.params.id));
  if (!course)
    res.status(404).send("The course with the given Id was not found");
  res.send(course);
});

// post api to add a course to courses array
app.post("/api/courses", (req, res) => {
  const course = {
    id: courses.length + 1,
    name: req.body.name,
  };
  courses.push(course);
  res.send(course);
});

// app.get('/api/courses/:year/:month', (req, res) => {
//     // res.send(req.params);
//     res.send(req.query);
// });

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}...`));
  • Okay to get the request body json with express we can use req.body and to get the specific field in the request body we can use req.body.<fieldName>. However, by default we can't do that because the req.body is the an object with type ReqBody and we need to use a Middleware express.json() to parse the req.body to json. Let's see the example below.

  • Firstly, we will tell Express to use the middleware express.json(). The express.json() is a built-in middleware function in the Express. Middleware functions in Express are functions that can process incoming HTTP requests before they reach the route handlers. express.json() middleware specifically parses incoming JSON payloads from HTTP requests and makes the parsed data available on the req.body property. It is designed to handle JSON data submitted in the request body, which is commonly used in API endpoints where clients send data in JSON format.

1
2
3
4
5
6
7
const express = require("express");
const app = express();

// use the middle ware
app.use(express.json());

//....
  • Now, we can get the specific field from req.body json.
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const express = require("express");
const app = express();

app.use(express.json());

const courses = [
  { id: 1, name: "course 1" },
  { id: 2, name: "course 2" },
  { id: 3, name: "course 3" },
];

app.get("/", (req, res) => {
  res.send("Hello World!!!");
});

app.get("/api/courses", (req, res) => {
  res.send(courses);
});

app.get("/api/courses/:id", (req, res) => {
  const course = courses.find((ci) => ci.id === parseInt(req.params.id));
  if (!course)
    res.status(404).send("The course with the given Id was not found");
  res.send(course);
});

app.post("/api/courses", (req, res) => {
  const course = {
    id: courses.length + 1,
    name: req.body.name,
  };
  courses.push(course);
  res.send(course);
});

// app.get('/api/courses/:year/:month', (req, res) => {
//     // res.send(req.params);
//     res.send(req.query);
// });

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}...`));
  • Okay, let's use postman and call POST /api/courses with request body as below. Then we will receive a successful response.
1
2
3
{
    "name": "Express Course"
}

nodejs-express-example-post-api-call.png

  • Now, let call api GET /api/courses. Then we can see the new course had been added into the mock courses array.

nodejs-express-example-get-all-with-new-item.png

Input Validation With Joi#

  • Okay, when we work with request body of POST Apis we may need to do some validations on fields of request body. In nodejs there is a powerful library can support us which is Joi.
  • Joi is a popular and powerful library for input validation and data schema validation in NodeJs applications. It is commonly used with Express to validate and sanitize data received from clients in API requests or any other input data that needs validation.
  • With Joi, we can define a schema for the expected data and validate incoming data against that schema. It allows us to ensure that the data conforms to specific rules, such as required fields, data types, length, format, and more. By validating input data, we can prevent invalid or malicious data from being processed by your application, enhancing security and reliability.
  • Now, to using Joi in our node application we will need to install it by using the command below.
1
npm install joi
  • After that, we will import the Joi object into our index.js for using.
index.js
1
2
3
4
5
const Joi = require("joi");
const express = require("express");
const app = express();

//....
  • Now, let's use joi to validate the request body in the POST Api as below.
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const Joi = require("joi");
const express = require("express");
const app = express();

app.use(express.json());

const courses = [
  { id: 1, name: "course 1" },
  { id: 2, name: "course 2" },
  { id: 3, name: "course 3" },
];

app.get("/", (req, res) => {
  res.send("Hello World!!!");
});

app.get("/api/courses", (req, res) => {
  res.send(courses);
});

app.get("/api/courses/:id", (req, res) => {
  const course = courses.find((ci) => ci.id === parseInt(req.params.id));
  if (!course)
    res.status(404).send("The course with the given Id was not found");
  res.send(course);
});

// create a Joi schema to validate request body json. 
app.post("/api/courses", (req, res) => {
  const schema = Joi.object({
    name: Joi.string().min(3).required()
  });
  const result = schema.validate(req.body);
  if (result.error) {
    res.status(400).send(result.error.details);
    return;
  }
  const course = {
    id: courses.length + 1,
    name: req.body.name,
  };
  courses.push(course);
  res.send(course);
});

// app.get('/api/courses/:year/:month', (req, res) => {
//     // res.send(req.params);
//     res.send(req.query);
// });

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}...`));
  • Okay we have const schema = Joi.object({ name: Joi.string().min(3).required() });. This is a Joi schema definition. It defines the validation rules for the incoming data in the request body. In this case, it specifies that the name property must be a string, have a minimum length of 3 characters, and be required (i.e., it cannot be empty).
  • Next we have const result = schema.validate(req.body);: Here, the incoming data in the request body (req.body) is validated against the defined schema using the validate method of the Joi schema object. The result variable will hold the validation result, which includes an error property if the validation fails.
  • Okay now, let's use postman and test with invalid data as below.

 #zoom

 #zoom

  • The failed HTTP status and error details will be through if the request body doesn't match with the the validation rules.

Handling HTTP Put Requests#

  • Next, we will continue to create a new PUT Api /api/courses/:id for updating a course in the mock array. In this Api we will do some validations.
    • Firstly, we will check the course id existed in the mock array or not.
    • Then we will check the request body is valid or not.
  • Okay, let's see the example code below.
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
const Joi = require("joi");
const express = require("express");
const app = express();

app.use(express.json());

const courses = [
  { id: 1, name: "course 1" },
  { id: 2, name: "course 2" },
  { id: 3, name: "course 3" },
];

app.get("/", (req, res) => {
  res.send("Hello World!!!");
});

app.get("/api/courses", (req, res) => {
  res.send(courses);
});

app.get("/api/courses/:id", (req, res) => {
  const course = courses.find((ci) => ci.id === parseInt(req.params.id));
  if (!course)
    res.status(404).send("The course with the given Id was not found");
  res.send(course);
});

app.post("/api/courses", (req, res) => {
  const { error } = validateCourse(req.body);
  if (error) {
    res.status(400).send(error.details);
    return;
  }
  const course = {
    id: courses.length + 1,
    name: req.body.name,
  };
  courses.push(course);
  res.send(course);
});

app.put("/api/courses/:id", (req, res) => {
  const course = courses.find((ci) => ci.id === parseInt(req.params.id));
  if (!course)
    res.status(404).send("The course with the given Id was not found");

  const { error } = validateCourse(req.body);
  if (error) {
    res.status(400).send(error.details);
    return;
  }

  course.name = req.body.name;
  res.send(course);
});

// app.get('/api/courses/:year/:month', (req, res) => {
//     // res.send(req.params);
//     res.send(req.query);
// });

function validateCourse(course) {
  const schema = Joi.object({
    name: Joi.string().min(3).required(),
  });
  return schema.validate(course);
}

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}...`));
  • As you can see, we will refactor the code a little bit with function validateCourse, we will use it for POST and PUT Apis. For the result of function validateCourse we are using the syntax { error } it means in the returned object we only get the error field.

  • Okay now, let's use postman to test this api.

 #zoom

  • We will get error if the request body is not correct or the id is not found.

 #zoom

 #zoom

 #zoom

  • Then if everything is correct then we can see the course with id is updated.

 #zoom

 #zoom

Handling HTTP Delete Requests#

  • Next, we will continue to create a new DELETE Api /api/courses/:id for deleting a course in the mock array. In this Api we just check the course id existed in the mock array or not.
  • Okay, let's see the example code below.
index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
const Joi = require("joi");
const express = require("express");
const app = express();

app.use(express.json());

const courses = [
  { id: 1, name: "course 1" },
  { id: 2, name: "course 2" },
  { id: 3, name: "course 3" },
];

app.get("/", (req, res) => {
  res.send("Hello World!!!");
});

app.get("/api/courses", (req, res) => {
  res.send(courses);
});

app.get("/api/courses/:id", (req, res) => {
  const course = courses.find((ci) => ci.id === parseInt(req.params.id));
  if (!course)
    return res.status(404).send("The course with the given Id was not found");
  res.send(course);
});

app.post("/api/courses", (req, res) => {
  const { error } = validateCourse(req.body);
  if (error) return res.status(400).send(error.details);

  const course = {
    id: courses.length + 1,
    name: req.body.name,
  };
  courses.push(course);
  res.send(course);
});

app.put("/api/courses/:id", (req, res) => {
  const course = courses.find((ci) => ci.id === parseInt(req.params.id));
  if (!course)
    return res.status(404).send("The course with the given Id was not found");

  const { error } = validateCourse(req.body);
  if (error) return res.status(400).send(error.details);

  course.name = req.body.name;
  res.send(course);
});

app.delete("/api/courses/:id", (req, res) => {
  const course = courses.find((ci) => ci.id === parseInt(req.params.id));
  if (!course)
    return res.status(404).send("The course with the given Id was not found");

  const index = courses.indexOf(course);
  courses.splice(index, 1);

  res.send(course);
});

// app.get('/api/courses/:year/:month', (req, res) => {
//     // res.send(req.params);
//     res.send(req.query);
// });

function validateCourse(course) {
  const schema = Joi.object({
    name: Joi.string().min(3).required(),
  });
  return schema.validate(course);
}

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}...`));
  • As we can see the delete Api is very simple, we just do the check and then delete the item in the array.
  • In the example code above, we also did some bug fixes at validation steps, we will add the returnerror right at these steps to make sure if the validation is failed then the code will not continue to run to the end of the Api function.

  • Now, let's use postmand and test the delete api.

 #zoom

  • We will get error if the request body is not correct or the id is not found.

 #zoom

  • If the id exists in the mock array then we can see the successful result as below.

 #zoom

 #zoom

See Also#

References#