History: Node.js and Heroku

Revision made 8 years ago by Francisco Presencia. Go to the last revision.

Let's learn how to use javascript to program a server based on Node.js and upload the website to Heroku. First, a simple server; write this in a file called app.js:

var express = require('express');
var app = express();

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

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

Then in a file called .gitignore we will write this:

node_modules

Lastly, let's install express, our server framework.

npm install express --save

We will also install nodemon since it makes things much easier:

npm install nodemon -g

Now we can see that message on the server. Run nodemon and open localhost:3000:

nodemon

Routing

Now let's tell our server what files and how it should display. First let's just display index.html. In app.js, write this instead of our previous 'Hello world':

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html');
});

If we reopen localhost:3000 and refresh it we can see our index.html without any style or javascript.

Then we also want our server to know where our css and (front-end) javascript is, so we will add this and put those files in there:

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

Now let's catch the files dynamically (routing). We will get the url fragment as the variable path and then use it:

app.get('/:name', function (req, res) {
  console.log(req.params);
  res.send(req.params);
});

The previous one only shows us in the terminal what file we are reading, now let's actually show it:

app.get('/:name', function (req, res) {
  var file = __dirname + '/' + req.params.name + '.html';
  res.sendFile(file);
});

Forms

Let's try to create a form and handle it with Node.js. First we create the form in contact.html:

<!DOCTYPE html>
<html>
  <head>
    <title>Página Web</title>
    <meta charset="utf-8">
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/picnicss/6.1.1/picnic.min.css">
    <link rel="stylesheet" href="style.css">
  </head>
  <body>

    <form action="/contacto" method="POST" class="contact">
      <h1>Contacto</h1>
      <input name="name" placeholder="Nombre">
      <input name="lastname" placeholder="Apellidos">
      <input name="age" placeholder="Edad">
      <input type="submit" value="Enviar">
    </form>

  </body>
</html>

And in style.css:

.contact {
  width: 500px;
  margin: 100px auto;
}

.contact input {
  margin-top: 0;
  margin-bottom: 10px;
}

Then we install body-parser, it's a library to read easier the forms from the back-end:

npm install body-parser --save

After that, in app.js we setup the library:

var bodyparser = require('body-parser');

// ...

app.use(bodyparser.urlencoded({ extended: false }));

Now we can use it to read the data. So far we won't be storing it, just display it on the terminal:

app.post('/contact', function(req, res){
  console.log(req.body);
  res.redirect('/');
});

If everything worked fine, this should accept our data from the contact form and then redirect us home. We could change this for a /thankyou.html page or just handle it with javascript on the front-end and not redirect anywhere.

REST API

A REST API is a group of URLs and actions that can be done to them (GET, POST, PUT, DELETE). Let's say we have a user system. This would be a basic REST API for it:

GET /users            # Get all of the users data
GET /users/456546     # Get one specific user data
POST /users           # Create a new user
PUT /users/435465     # Edit an existing user
DELETE /users         # Remove all the users
DELETE /users/354643  # Remove a single user

This is useful on its own, but specially useful with React.js, Angular, etc. It is also used with mobile apps as well as webapps. It separates our logic at some specific points and makes it easier to handle the complexity.

Let's make a small API that handles a Like button. In our app.js:

// An array with the ids of the things we liked
var likes = [];

// Retrieve all of our likes
app.get('/likes', function(req, res){
  res.json(likes);
});

// Create a new like
app.post('/likes/:id', function(req, res){
  var id = req.params.id;
  likes.push(req.params.id);
  res.json({ added: true });
});

app.delete('/likes/:id', function(req, res){
  var id = req.params.id;
  var index = likes.indexOf(id);
  likes.splice(index, 1)
  res.json({ deleted: true });
});

Now we can have a list of items that can be liked:

<main>
  <ul>
    <li>First <button data-id="1">Like</button></li>
    <li>Second <button data-id="2">Like</button></li>
    <li>Third <button data-id="3">Like</button></li>
    <li>Fourth <button data-id="4">Like</button></li>
  </ul>
</main>

<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>
  // Load all the likes and add the class 'active' to the ones we liked
  $(document).ready(function(){
    $.get('/likes/', function(likes){
      likes.forEach(function(id){
        $('button[data-id="' + id + '"]').addClass('active');
      });
    });
  });

  // Handle the button clicks
  $('button').on('click', function(e){
    var id = $(e.target).attr('data-id');
    var isLiked = $(e.target).hasClass('active');

    $.ajax({
      url: '/likes/' + id,
      method: isLiked ? 'DELETE' : 'POST',
      success: function(){
        $(e.target).toggleClass('active');
        console.log('Good job!');
      }
    });
  });
</script>

Exercise: make a dislike button that calls the route /dislike through POST and DELETE and shows on the browser console what the server is doing.