Lesson 1: A Hello World for Node.js and Express

We’re going to build a basic Node.js server that uses Express for the
API.

Initialize a new node project

The first step with Node.js is to initialize a new project. You do
this with npm init.

1
2
3
mkdir lesson1
cd lesson1
npm init

This will ask you a number of questions. Here is how I answered them:

1
2
3
4
5
6
7
8
9
package name: (lesson1)
version: (1.0.0)
description: hello world
entry point: (index.js) server.js
test command:
git repository:
keywords:
author:
license: (ISC)

Now you need to install Express. This will automatically save express
as a dependency in package.json:

1
npm install express

Tip: when putting code into a repository that uses node.js, be
sure to create a file called .gitignore in the top level of your
repository that contains:

1
node_modules

This will prevent you from adding the node modules directory, which
often contains many libraries, into your git repository. Instead,
because you have a package.json, anyone can use npm install to
install all the dependencies for your project. To see how this works,
you can always try cloning your repository to a new directory and do
npm install there.

Hello World

We’re now going to build a basic node server with Express. Create a
file called server.js that contains:

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

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

app.listen(3000, () => console.log('Server listening on port 3000!'));

When you run node server.js, your server will run and listen on port 3000. You can visit it in a browser at localhost:3000.

In this example, we are using require to include the Express
module. A good explanation of how require works is at this article
called Requiring modules in Node.js: Everything you need to know.

express() is the top-level function exported by Express. There are a
number of functions defined on this in the API
documentation
.

The next section defines what the server will do when it receives a
GET request for /. It defines a function that takes request and
response objects, then just sends a string response. This is what the
browser displays when it visits the root of the server.

Finally, the last line starts a web server that listens on port 3000
for incoming requests.

You can run this code with Node.js:

1
node server.js

You can stop it by entering control-c.

REST API

When you define an API, you can technically follow any rules you would
like. However, many people (loosely, or sometimes strictly) follow a
design known as REST. If you would like to learn more, this is a good
REST API
Tutorial
.

For now, we’ll just introduce the convention used for the HTTP
methods. Typically these methods are used in these situations:

Method Purpose
POST Create an object
GET Read an object
PUT Update an object
DELETE Delete an object

Notice that if you read down, the letters spell CRUD. This is a common
acronym for APIs and databases, representing the four basic operations
you can perform.

Add these lines to server.js, just before the call to listen:

1
2
3
4
5
6
7
8
9
10
11
app.post('/', (req, res) => {
res.send('Here is the response to your POST, man!\n');
});

app.put('/', (req, res) => {
res.send('I am updated.\n');
});

app.delete('/', (req, res) => {
res.send('All my memories have been deleted. Are you happy now?\n');
});

These just illustrate the different methods. Normally, the methods
would access a database to create, update, or delete particular items
in the database.

You can access these URLs using curl:

1
2
3
4
curl -X GET localhost:3000/
curl -X POST localhost:3000/
curl -X PUT localhost:3000/
curl -X DELETE localhost:3000/

Naming your resources

We can add any kind of path for the API. For example, add these lines
to server.js, just before the call to listen:

1
2
3
4
5
6
7
8
9
10
11
app.get('/secret', (req, res) => {
res.send('Psst. You are being watched.\n');
});

app.get('/api/user/1', (req, res) => {
res.send({
name: "Amy Caprietti",
avatar: "/avatars/supergirl.jpg",
role: "admin"
});
});

Test with:

1
2
curl -X GET localhost:3000/secret
curl -X GET localhost:3000/api/user/1

Notice that we can return JSON responses.

When it comes to designing a RESTful API, there are a number of rules
… er, guidelines … that people
follow
.

guidelines

For example, if you build a web site for an art museum, your server
may need an API that does some of the following:

Route HTTP method Description
/api/art GET get all the art pieces held by the museum
/api/art POST create a new art piece held by the museum
/api/art/:id GET get a single art piece
/api/art/:id PUT update the information about a single art piece
/api/art/:id DELETE delete the information about a single art piece

Here is an example of how to use these routes:

1
2
3
4
5
GET /art - Retrieves a list of all the art pieces
GET /art/12 - Retrieves art piece #12
POST /art - Creates a new art piece
PUT /art/12 - Updates art piece #12
DELETE /art/12 - Deletes art piece #12

Lesson 2: A help ticket server

Let’s build a help ticket server and a Vue front end for submitting tickets. We’ll assume a ticket has a name and a problem being reported.

The first step is to initialize a new project. You do
this with npm init.

1
2
3
mkdir lesson2
cd lesson2
npm init

Like the first lesson, we’ll answer these questions:

1
2
3
4
5
6
7
8
9
package name: (lesson2)
version: (1.0.0)
description: help ticket server
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)

Now we need to install Express and an npm library for parsing the body of POST requests.

1
npm install express body-parser

Next, create a file called tickets.js with the following code:

1
2
3
4
5
6
const express = require('express');
const bodyParser = require("body-parser");

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

This includes the modules we’re using and initializes them.

1
app.use(express.static('public'));

This tells Express that it should serve any files in the public directory as if they were just
static files on a web server. We’ll put our Vue code here later on.

1
2
let tickets = [];
let id = 0;

Since we don’t have a database setup yet, we’re just going to store our tickets in a global variable.

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

This is the REST endpoint for getting all the tickets in the system. We just send our list,
which by default comes with a 200 OK response.

1
2
3
4
5
6
7
8
9
10
app.post('/api/tickets', (req, res) => {
id = id + 1;
let ticket = {
id: id,
name: req.body.name,
problem: req.body.problem
};
tickets.push(ticket);
res.send(ticket);
});

This is the REST endpoint for creating a new ticket. We get the parameters from the request body,
create a new ticket, then send back the same ticket we created in a 200 OK response. We’ve left out
some error checking—we should check whether the request body includes the desired information.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.delete('/api/tickets/:id', (req, res) => {
let id = parseInt(req.params.id);
let removeIndex = tickets.map(ticket => {
return ticket.id;
})
.indexOf(id);
if (removeIndex === -1) {
res.status(404)
.send("Sorry, that ticket doesn't exist");
return;
}
tickets.splice(removeIndex, 1);
res.sendStatus(200);
});

This is the REST endpoint for deleting a ticket. The ID is passed in the URL so we use a different
method to parse it. We check whether this ID is present and return a 404 error if it doesn’t.
Otherwise, we remove it and return 200 OK.

1
app.listen(3000, () => console.log('Server listening on port 3000!'));

This starts the server on port 3000.

Testing with curl

Run the server:

1
node tickets.js

Then you can test it with curl:

1
2
3
4
5
6
7
8
9
10
11
$ curl -d '{"name":"Daniel","problem":"Nothing works! This software is junk!"}' -H "Content-Type: application/json" -X POST localhost:3000/api/tickets
{"id":1,"name":"Daniel","problem":"Nothing works! This software is junk!"}

$ curl localhost:3000/api/tickets
[{"id":1,"name":"Daniel","problem":"Nothing works! This software is junk!"}]

$ curl -d '{"name":"Daniel","problem":"Never mind, this system is cool. It was a feature, not a bug!"}' -H "Content-Type: application/json" -X POST localhost:3000/api/tickets
{"id":2,"name":"Daniel","problem":"Never mind, this system is cool. It was a feature, not a bug!"}

$ curl localhost:3000/api/tickets
[{"id":1,"name":"Daniel","problem":"Nothing works! This software is junk!"},{"id":2,"name":"Daniel","problem":"Never mind, this system is cool. It was a feature, not a bug!"}]

Vue front end

In the public directory, you’ll find a Vue front end for adding and deleting tickets. This code
should be easy to follow given what we’ve done with Vue so far.

When you run node tickets.js, then the node server will deliver
/public/index.html because we have included this line:

1
app.use(express.static('public'));

This causes the browser to load the HTML, CSS, and JavaScript for the front end. Inside this code, you’ll see some methods that use axios to call the REST API defined by the back end in tickets.js.

Let’s run through each of these methods:

1
2
3
4
5
6
7
8
9
async getTickets() {
try {
let response = await axios.get("http://localhost:3000/api/tickets");
this.tickets = response.data;
return true;
} catch (error) {
console.log(error);
}
},

This method uses the REST API to get the current list of tickets. It puts the response data directly into the tickets property, which is displayed in index.html.

Note that we call this method when the Vue instance is created. See the created() section. We also call it whenever we change the set of tickets.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
async addTicket() {
try {
let response = await axios.post("http://localhost:3000/api/tickets", {
name: this.addedName,
problem: this.addedProblem
});
this.addedName = "";
this.addedProblem = "";
this.getTickets();
return true;
} catch (error) {
console.log(error);
}
},

This method uses the REST API to create a new ticket. Typically a REST API uses POST to create a new resource and UPDATE to edit it. Because this is a POST request, we supply a body that includes two properties needed by the API: name, and problem.

Once we create the new ticket, we call the API to fetch the list of tickets.

1
2
3
4
5
6
7
8
9
10
async deleteTicket(ticket) {
try {
let response = axios.delete("http://localhost:3000/api/tickets/" + ticket.id);
this.getTickets();
return true;
} catch (error) {
console.log(error);
}
}

This method uses the REST API to delete a ticket. We supply the specific ID of the ticket we are deleting by appending it to the URL. Notice that we get this ticket ID from index.html. When we iterate through the list of tickets using v-for, we can pass ticket to the deleteTicket method.