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:
- Getting started with Node.js
- Using NPM
- Understanding async programming
- Your first Node.js HTTP server [you are reading it now]
- Node.js Database Tutorial
- Node.js request module tutorial
- Node.js project structure tutorial
- Node.js authentication using Passport.js
- Node.js unit testing tutorial
- Debugging Node.js applications
- Node.js Security Tutorial
- How to Deploy Node.js Applications
- 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 visitlocalhost:3000
from your browser, two log messages will appear: one for/
and one forfavicon.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.
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 thenext
callback. Callingnext
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