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 placeholder="Nombre">
      <input placeholder="Apellidos">
      <input 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 one group of url and action that can be done to them. For instance, let's say we have a user system. This would be a basic REST API:

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 for example with React.js, Angular, etc. 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(){
  res.json({
    likes: 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>
  // Load all the likes and add the class 'active' to the ones we liked
  $(document).ready(function(){
    $.get('/likes/', function(res){
      res.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, {
      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.