Skip to content

M07 - Express

Introduction

Express is a free and open-source Node.js web application server framework which is specifically designed for the building a web applications. It is the most popular choice to building web applications with a Node.js. Express is basically a fairly simple server application framework. It's one of the more stable packages in the JavaScript ecosystem, meaning that it doesn't get a new release every two weeks. It's been a safe bet in many real life projects.

It's a framework that let's you structure a server application to handle multiple different HTTP requests at a specific url. It integrates with "view" rendering engines in order to generate responses by inserting data into templates. However in this course we only create an endpoints/routes to return data to the client, but of course you can use it's template engine to generate a views too.

Express adds additional request processing "middleware" at any point within the request handling pipeline. While Express itself is fairly minimalist, developers have created compatible middleware packages to address almost any web development problem. There are libraries to work with cookies, sessions, user logins, URL parameters, POST data, security headers, and many more. You can find a list of middleware packages maintained by the Express team at Express Middleware (along with a list of some popular 3rd party packages).

With Express you are building server applications / backend applications. As a backend application, Node.js application, it is like a glue between frontend application and database or other data source in backend.

Links:

Install Express

You can install Express in your app directory and save it in the dependencies list with below command:

1
npm install express

Above command will install the express module into node_modules in the current directory. And it will include express dependency in your package.json file. Express version is 4.18.1.

1
2
3
4
5
6
{
  // ...
  "dependencies": {
    "express": "^4.18.1"
  }
}

Running a web server

Create Node.js project and modify index.js to use express (import it and create express app) and start a web server.

1
2
3
4
5
6
7
const express = require('express') 
const app = express()
const port = 3000

app.listen(port, () => {
  console.log('Example app listening on port 3000')
})

Once you start your application on the command line with node index.js, you should be able to see the output in the command line:

1
2
node index.js
Example app listening on port 3000

Remember, that you should edit your package.json and create a new start script to launch your project.

1
2
3
4
"scripts": {
    "start": "node index.js"
    //...
  },

Now launch your project with npm start command.

1
2
3
4
5
6
npm start

> webserver1@1.0.0 start /Users/pasi/Node/express/webserver1
> node index.js

Example app listening on port 3000

Your Express web server is up and running. Application is available at http://localhost:3000 in the browser. If you try this address, nothing is available because any routes/endpoints aren't defined.

Nodemon

Install nodemon to automatically restarting the node application when file changes in the directory are detected.

  • Give command npm install --save-dev nodemon
  • Edit package.json file to start nodemon

1
2
3
4
5
"scripts": {
  "start": "node index.js",
  "dev": "nodemon index.js",
  "test": "echo \"Error: no test specified\" && exit 1"
},
* Start your project with nodemon npm run dev

REST

REST (REpresentational State Transfer) is an architectural style to provide communication between different computer systems. It is mostly used between the client and the server communication in web application. The main idea is that the client and the server is working independently without knowing about the other one. Communication that uses the REST are said to be stateless, which means that the server does not need to know anything about what state the client has and vice versa.

In this architecture, a REST server provides connectivity to resources, which helps client to access server application data. These resources are recognized by the URIs. In a web applications, these resources are used with HTTP-protocol requests.

In a server side, a server will receive requests, processes them and returns a response to the caller for example with text, HTML, JSON or XML format.

The requests have a few major types (CRUD):

  • POST request sends data (C, create)
  • GET request get’s data (R, read)
  • PUT request updates data (U, update)
  • DELETE request deletes data (D, delete)

REST was defined in 2000 by Roy Fielding's dissertation. It’s not a standard but a set of recommendations and constraints for RESTful web services, which includes following:

Routes/endpoints

You will need to create routes/endpoints to your Node application. Routing refers to determining how a server side application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on). Each route can have one or more handler functions, which are executed when the route is matched. These handler functions can return text messages, HTML page or somekind of data like JSON, etc... to caller client. In a larger application you would have several routes to handle several URI's.

Route definition takes the following structure:

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

// METHOD is the HTTP method of the request, such as GET, PUT, POST, etc...
// PATH is a path on the server.
// HANDLER is the function executed when the route is matched.
app.METHOD(PATH, HANDLER)

Example GET request to /hello path to respond with 'Hello Express!' text.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const express = require('express') 
const app = express()
const port = 3000

app.get('/hello', (request, response) => {
  response.send('Hello Express!')
})

app.listen(port, () => {
  console.log('Example app listening on port 3000')
})

The above Node.js based express application is running on the local computer. The application is available in the browser at http://localhost:3000/hello. The text Hello Express! should now appear in the browser.

Method

For a full list, see app.METHOD. You can also use app.all() to handle all HTTP methods.

Usually application describes CRUD requests:

  • POST request sends data (C, create)
  • GET request get’s data (R, read)
  • PUT request updates data (U, update)
  • DELETE request deletes data (D, delete)

Path

Route paths, in combination with a request method, define the endpoints at which requests can be made. Route paths can be strings, string patterns, or regular expressions.

Here are a few examples:

1
2
3
app.get('/', (request, response) => {
  response.send('about')
})
1
2
3
app.get('/login', (request, response) => {
  response.send('My login route')
})
1
2
3
4
// route path will match /abe and /abcde
app.get('/ab(cd)?e', (request, response) => {
  response.send('regex')
})
1
2
3
app.put('/user', (request, response) => {
  res.send('Got a PUT request at /user')
})
1
2
3
app.delete('/user', (request, response) => {
  res.send('Got a DELETE request at /user')
})

Parameters

Route parameters are named URL segments that are used to capture the values specified at their position in the URL. The captured values are populated in the req.params object, with the name of the route parameter specified in the path as their respective keys.

Example: Let's think of a situation where the client application would like to request from the server (GET request), for example, the data of the 10th client's 100th task (some Todo-type application would be in use).

Request can be:

1
Request URL: http://localhost:3000/users/10/todos/100

To define route with route parameters, simply specify the route parameters in the path of the route as shown below.

1
2
3
4
5
app.get('/users/:userId/todos/:todoId', (request, response) => {
  // code here... now only send request params back to the caller
  // normally read data from database and return it....
  response.send(request.params)
})
The above programming would therefore use the request.params object with the following values:

1
request.params: { "userId": "10", "todoId": "100" }

Handler callback

These routing methods specify a callback function (sometimes called "handler functions") called when the application receives a request to the specified route (endpoint) and HTTP method.

In a below callback function only send response back to the caller.

1
2
3
app.get('/about', function (request, response) {
  response.send('about')
})

Or you can use array functions.

1
2
3
app.get('/about', (request, response) => {
  response.send('about')
})

The routing methods can have more than one callback function as arguments. With multiple callback functions, it is important to provide next as an argument to the callback function and then call next() within the body of the function to hand off control to the next callback.

1
2
3
4
5
6
7
app.get('/', (request, response, next) => {
  console.log('Executing the 1st callback function')
  next()
}, (request, response) => {
  console.log('Executing the 2nd callback function')
  response.send('Hello Express!')
})

Create a request to your localhost and you should see a 'Hello Express!' text in your browser and folloing text lines in your terminal.

1
2
3
Example app listening on port 3000
Executing the 1st callback function
Executing the 2nd callback function

Note

Remember send response to the client with one of the following Response methods or the client request will be left hanging.

Example

Create a new Node project.

1
2
3
mkdir example
cd example
npm init

Answer project based questions and package.json will be generated.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package name: (example) 
version: (1.0.0) 
description: Testing Express
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: Pasi Manninen
license: (ISC) 
About to write to /Users/pasi/JamkFullStack/express/example/package.json:

{
  "name": "example",
  "version": "1.0.0",
  "description": "Testing Express",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Pasi Manninen",
  "license": "ISC"
}

Modify package.json to have own starting script.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "name": "example",
  "version": "1.0.0",
  "description": "Testing Express",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Pasi Manninen",
  "license": "ISC"
}

Install Express

Add Express and Nodemon to your project.

1
2
npm install express
npm install --save-dev nodemon

Note, that dependencies will be added to package.json. Express and nodemon files be added to your project node_modules folder.

Modify package.json file to use dev keyword start project with nodemon.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "name": "example",
  "version": "1.0.0",
  "description": "Testing Express",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Pasi Manninen",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.1"
  }
}

Programming routes

Create index.js file and create Express application to your Node application.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// use express
const express = require('express') 

// create express app
const app = express()

// define port
const port = 3000

// define endpoint
app.get('/', (request, response) => {
  response.send('Hello from server side!')
})

// start web-server and listen port 3000
app.listen(port, () => {
  console.log('Example app listening on port 3000')
})

Save file and start your Node based application with nodemon.

1
npm run dev

In above example, first parameter in the get route function is the route used and second one is the event handler which handles all the HTTP GET calls to this route.

Now the response object is used with send method to send string content back to client application / browser. Express will automatically add content-type header value as a text/html and status code 200.

Image 01

Test now http://localhost:3000 address in the browser and you should see Hello Express! text in your browser. If you test some other "routes" like: http://localhost:3000/test, it won't work because that route is not served. You should get Cannot GET /test text.

Lets add one more route to our app. Modify your application support /test route too.

1
2
3
app.get('/test', (request, response) => {
  response.send('Test route!')
})

Now both of the routes should work http://localhost:3000 and http://localhost:3000/test.

Create one more route, which returns some JSON to the caller browser. Now you can use json method with response object. This json method sends JSON string back to caller browser and Express set header Content-type value as a application/json automatically.

1
2
3
4
5
6
// define some data with JSON format
let person = {'name':'Kirsi Kernel'}

app.get('/json', (request, response) => {
  response.json(person)
})

Try now http://localhost:3000/json and check returned Content-Type from your browser's Inspector Network tab. It should be Content-Type: application/json; charset=utf-8.

It is easy to test GET requests to the server with a web browser, but how can you test and implement other CRUD requests? Visual Studio Code's Rest Client or a separate Postman application can be used.

Visual Studio Code - Rest Client

Install the Visual Studio Code REST Client. This client plugin allows send REST requests from Visual Studio Code to the server.

Add a folder called rest to the project and make the get_person.rest file there. Program the following content.

Image 02

Press the Send request text above the code. VS Code REST client sends a request to the server and displays the response in a separate window.

Image 03

Ok, now GET request is tested and let's go back to configuring the PUT request. Make a new post_person.rest file and program the following content.

Image 04

The JSON object presented above comes to the server as a string, so here it is worth using Express's json middleware, which can change the JSON string that arrives on the server into a JSON object.

Use Express's json middleware in server side programming.

1
2
// Use JSON parser
app.use(express.json())

Add a new route/endpoint which handles POST request.

1
2
3
4
5
6
7
8
app.post('/person', (request, response) => {
  // get request body with JSON
  const body = request.body
  console.log(body.name)
  console.log(body.age)
  console.log(body.email)
  response.send('POST HTTP received!')
})

Sent JSON data can be found from request.body object. Now above route only displays name, age and email values to console and sends POST HTTP received! string back to the caller application.

Note

You can test other CRUD-methods in same way.

Postman

Use Postman to test different RESTful HTTP request to your server.

Image 05