Tuesday, January 17, 2017

Your First Node.js HTTP Server

This is the 4th post of the tutorial series called Node Hero - in these chapters you can learn how to get started with Node.js and deliver software products using it.
In this chapter, I’ll guide you how you can fire up a simple Node.js HTTP server and start serving requests.
Upcoming and past chapters:
  1. Getting started with Node.js
  2. Using NPM
  3. Understanding async programming
  4. Your first Node.js HTTP server [you are reading it now]
  5. Node.js Database Tutorial
  6. Node.js request module tutorial
  7. Node.js project structure tutorial
  8. Node.js authentication using Passport.js
  9. Node.js unit testing tutorial
  10. Debugging Node.js applications
  11. Node.js Security Tutorial
  12. How to Deploy Node.js Applications
  13. Monitoring Node.js Applications

The http module for your Node.js server

When you start building HTTP-based applications in Node.js, the built-in http/https modules are the ones you will interact with.
Now, let's create your first Node.js HTTP server! We'll need to require the http module and bind our server to the port 3000 to listen on.
// content of index.js
const http = require('http')  
const port = 3000

const requestHandler = (request, response) => {  
  console.log(request.url)
  response.end('Hello Node.js Server!')
}

const server = http.createServer(requestHandler)

server.listen(port, (err) => {  
  if (err) {
    return console.log('something bad happened', err)
  }

  console.log(`server is listening on ${port}`)
})
You can start it with:
$ node index.js
Things to notice here:
  • requestHandler: this function will be invoked every time a request hits the server. If you visit localhost:3000 from your browser, two log messages will appear: one for / and one for favicon.ico
  • if (err): error handling - if the port is already taken, or for any other reason our server cannot start, we get notified here
The http module is very low-level - creating a complex web application using the snippet above is very time-consuming. This is the reason why we usually pick a framework to work with for our projects. There are a lot you can pick from, but these are the most popular ones:
For this and the next chapters we are going to use Express, as you will find the most modules on NPM for Express.

Express

Fast, unopinionated, minimalist web framework for Node.js - http://expressjs.com/
Adding Express to your project is only an NPM install away:
$ npm install express --save
Once you have Express installed, let's see how you can create a similar application as before:
const express = require('express')  
const app = express()  
const port = 3000

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

app.listen(port, (err) => {  
  if (err) {
    return console.log('something bad happened', err)
  }

  console.log(`server is listening on ${port}`)
})
The biggest difference what you have to notice here is that Express by default gives you a router. You don't have to check manually for the URL to decide what to do, but instead, you define the application's routing with app.get, app.post, app.put, etc. They are translated to the corresponding HTTP verbs.
One of the most powerful concepts that Express implements is the middleware pattern.

Middlewares

You can think of middlewares as Unix pipelines, but for HTTP requests.
Express middlewares for building a Node.js HTTP server
In the diagram you can see how a request can go through an Express application. It travels to three middlewares. Each can modify it, then based on the business logic either the third middleware can send back a response or it can be a route handler.
In practice, you can do it this way:
const express = require('express')  
const app = express()

app.use((request, response, next) => {  
  console.log(request.headers)
  next()
})

app.use((request, response, next) => {  
  request.chance = Math.random()
  next()
})

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

app.listen(3000)  
Things to notice here:
  • app.use: this is how you can define middlewares - it takes a function with three parameters, the first being the request, the second the response and the third one is the next callback. Calling next signals Express that it can jump to the next middleware or route handler.
  • The first middleware just logs the headers and instantly calls the next one.
  • The seconds one adds an extra property to it - this is one of the most powerful features of the middleware pattern. Your middlewares can append extra data to the request object that downstream middlewares can read/alter.

Error handling

As in all frameworks, getting the error handling right is crucial. In Express you have to create a special middleware function to do so - a middleware with four parameters:
const express = require('express')  
const app = express()

app.get('/', (request, response) => {  
  throw new Error('oops')
})

app.use((err, request, response, next) => {  
  // log the error, for now just console.log
  console.log(err)
  response.status(500).send('Something broke!')
})
Things to notice here:
  • The error handler function should be the last function added with app.use.
  • The error handler has a next callback - it can be used to chain multiple error handlers.

Rendering HTML

So far we have taken a look on how to send JSON responses - it is time to learn how to render HTML the easy way. For that, we are going to use the handlebars package with the express-handlebars wrapper.
First, let's create the following directory structure:
├── index.js
└── views
    ├── home.hbs
    └── layouts
        └── main.hbs
Once you have that, populate index.js with the following snippet:
// index.js
const path = require('path')  
const express = require('express')  
const exphbs = require('express-handlebars')

const app = express()

app.engine('.hbs', exphbs({  
  defaultLayout: 'main',
  extname: '.hbs',
  layoutsDir: path.join(__dirname, 'views/layouts')
}))
app.set('view engine', '.hbs')  
app.set('views', path.join(__dirname, 'views'))  
The code above initializes the handlebars engine and sets the layouts directory to views/layouts. This is the directory where your layouts will be stored.
Once you have this setup, you can put your initial html into the main.hbs - to keep things simple let's go with this one:
<html>  
  <head>
    <title>Express handlebars</title>
  </head>
  <body>
    {{{body}}}
  </body>
</html>  
You can notice the {{{body}}} placeholder - this is where your content will be placed - let's create the home.hbs!
<h2>Hello {{name}}<h2>  
The last thing we have to do to make it work is to add a route handler to our Express application:
app.get('/', (request, response) => {  
  response.render('home', {
    name: 'John'
  })
})
The render method takes two parameters:
  • The first one is the name of the view,
  • and the second is the data you want to render.
Once you call that endpoint you will end up with something like this:
<html>  
  <head>
    <title>Express handlebars</title>
  </head>
  <body>
    <h2>Hello John<h2>
  </body>
</html>  
This is just the tip of the iceberg - to learn how to add more layouts and even partials, please refer to the official express-handlebars documentation.

Debugging Express

In some cases, you may need to see what happens with Express when your application is running. To do so, you can pass the following environment variable to Express: DEBUG=express*.
You have to start your Node.js HTTP server using:
$ DEBUG=express* node index.js

No comments:

Post a Comment