Categories
Node.js Basics

Node.js Basics — HTTP

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

HTTP

The http module is a module that comes with the Node.js runtime environment.

We can use it to create a simple HTTP server.

All we have to do is to require the HTTP package by writing:

const http = require('http');
const server = http.createServer();
server.listen(8080, () => {
  console.log( 'Listening on port 8080' );
});

We require the HTTP module and then call the createServer method on the imported module to create our server.

Then we call the listen method on the server object to listen for requests on port 8080.

If we want to to handle requests and return responses, we can use the request and response parameters to get the request data and create the response respectively.

For example, we can write:

const http = require('http');
let count = 0;
const server = http.createServer((request, response) => {
  count += 1;
  response.writeHead(201, {
    'Content-Type': 'text/plain'
  });
  const message = `count: ${count}`;
  response.end(message);
});
server.listen(8080, () => {
  console.log('Listening on port 8080');
});

We use the methods in the response object to create the response that we return to the user.

We call the writeHead method with the status code and the response headers that we want to return.

The Content-Type header is set to text/plain so that we can let the client know what the data type of the response is.

201 status means a new object is created.

The response.end method lets us return the response body to the client.

To get request data, we can use the properties of the request parameter.

For example, we can write:

const http = require('http');
let count = 0;
const server = http.createServer((request, response) => {
  count += 1;
  response.writeHead( 201, {
    'Content-Type': 'text/plain'
  });
  const message = `count: ${count}, path: ${request.url}`;
  response.end(message);
});
server.listen(8080, () => {
  console.log('Listening on port 8080');
});

to get the path of the URL with the request.url property and return it with the response body.

Routing

Since we have access to the URL that the request is made to, we can do something according to the URL that the user is accessing.

For example, we can write:

const http = require('http');
let count = 0;
const server = http.createServer((request, response) => {
  let message,
    status = 200;
  count += 1;
  switch (request.url) {
    case '/count':
      message = count.toString();
      break;
    case '/hello':
      message = 'World';
      break;
    default:
      status = 404;
      message = 'Not Found';
      break;
  }
  response.writeHead(status, {
    'Content-Type': 'text/plain'
  });
  response.end(message);
});
server.listen(8080, () => {
  console.log('Listening on port 8080');
});

to send different responses according to the URL that is given.

If request.url is /count then we return the value of the count with the 200 status.

If request.url is /hello , then we return 'World' with the 200 status.

Otherwise, we return 'Not Found' with a 404 status.

Conclusion

We can create a simple HTTP server with the Node.js’s built-in http module.

Categories
Node.js Basics

Node.js Basics — Handle Complex HTTP Requests

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Complex Routing

It’s easy to do simple routing with our own code with our own HTTP server, but if we want to add more complex routing, then we can use the router module to help us do this.

To use it, we install the router and finalhandler packages by running:

npm i router finalhandler

to install the packages.

Then we can use it to handle requests by writing:

const finalhandler = require('finalhandler')
const http = require('http')
const Router = require('router')

const router = Router()
router.get('/', (req, res) => {
  res.setHeader('Content-Type', 'text/plain; charset=utf-8')
  res.end('Hello World!')
})

const server = http.createServer((req, res) => {
  router(req, res, finalhandler(req, res))
})

server.listen(8080)

We create the Router instance and then call the get method on it to create a GET route to let us handle GET requests to the / route.

The res.setHeader method lets us set the response header.

And the res.end method lets us set the response body.

To accept URL parameters, we can write:

const finalhandler = require('finalhandler')
const http = require('http')
const Router = require('router')

const router = Router({ mergeParams: true })
router.route('/pet/:id')
  .get(function (req, res) {
    res.setHeader('Content-Type', 'application/json')
    res.end(JSON.stringify({ name: 'tobi', id: req.params.id }))
  })
  .delete(function (req, res) {
    res.end()
  })
  .all(function (req, res) {
    res.statusCode = 405
    res.end()
  })

const server = http.createServer((req, res) => {
  router(req, res, finalhandler(req, res))
})

server.listen(8080)

We pass in an object to the Router function with the mergParams property set to true so that we can accept URL parameters.

Then we can use the route method to define routes that takes the id parameter.

The :id substring is the URL parameter placeholder for the id parameter.

Then we call res.setHeader to set the header.

And we use the req.params.id property to get the value of the id URL parameter.

We set the res.statusCode property to set the response status code.

The delete method lets us define a route to handle a DELETE request.

We can also add a middleware that runs before our routes run.

For example, we can write:

const finalhandler = require('finalhandler')
const http = require('http')
const Router = require('router')

const router = Router({
  mergeParams: true
})
router.use(function(request, response, next) {
  console.log('middleware executed');
  next(null);
});
router.route('/pet/:id')
  .get(function(req, res) {
    res.setHeader('Content-Type', 'application/json')
    res.end(JSON.stringify({
      name: 'tobi',
      id: req.params.id
    }))
  })
  .delete(function(req, res) {
    res.end()
  })
  .all(function(req, res) {
    res.statusCode = 405
    res.end()
  })

const server = http.createServer((req, res) => {
  router(req, res, finalhandler(req, res))
})

server.listen(8080)

We call the use method with a function. This function is called before any route handler is called.

Therefore, we should see 'middleware executed' string logged in the console.

The next function lets us call the route handler.

Conclusion

We can create more complex route handlers for our HTTP server with the router package.

Categories
Node.js Basics

Node.js Basics — Getting Started

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Installation

We can install the latest Node.js version at https://nodejs.org/en/download/

This lets us download binaries for Windows and macOS.

If we’re using Linux, then we can run:

# Using Ubuntu
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt-get install -y nodejs

# Using Debian, as root
curl -sL https://deb.nodesource.com/setup_14.x | bash -
apt-get install -y nodejs

to install Node.js 14.x.

Then we can create a file called example.js and write:

console.log("Hello world")

If we run node example.js , we should see ‘Hello world’ displayed.

Requiring Packages

Node.js comes with its own module system.

It uses the CommonJS module system which lets us import modules.

Modules are just JavaScript files that export something so other modules can use the exported items.

For example, to create and use modules, we can write:

index.js

const util = require("./utils");
util.logger.log("cool");

utils/index.js

const Logger = require("./logger");
exports.logger = new Logger();

utils/logger.js

class Logger{
  log(...args) {
    console.log(args);
  };
}
module.exports = Logger;

In the utils folder, we have 2 modules, which are index.js and logger.js

logger.js exports the Logger class by setting the class as the value of the module.exports property.

Then in utils/index.js , we called require with the relative path to the logger.js file to import the Logger class.

We export the logger by creating the exports.logger property and then assigning the Logger instance to it.

Then in index.js , we call require to import utils/index.js by writing:

const util = require("./utils");

If the file we require is called index.js , then we don’t need to include the file name.

Also, we don’t need to include the file extension for JavaScript modules.

Then to call the log method, we run:

util.logger.log("This is pretty cool");

We access exports.logger by using the utils.logger property.

Now we should see 'cool' displayed on the screen.

NPM

NPM is the most popular package manager for JavaScript apps.

To download packages with it, we can run the npm install command.

For example, if we want to install the chalk package so that we can see colored text on our console, we run npm install chalk .

Then we can use the package by writing:

const chalk = require("chalk");
console.log("I am just normal text")
console.log(chalk.green( "I am green text" ))

We call chalk.green by calling the chalk.green method from the chalk package.

The module will be installed into the node_modules folder of your project folder.

When we require it, it’ll automatically be picked up by Node.js from that folder.

Then package.json and package-lock.json file will be created when we install the packages.

If they aren’t there, we can run:

npm init

to add those files.

We’ll be asked some questions like the project name and other project data.

Conclusion

We can create Node.js apps by creating modules or using third party modules and use them in our own modules.

Categories
Node.js Basics

Node.js Basics — Add Authentication to an Express App with Passport

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Authentication

In the real world, many HTTP requests can only be made when the user is authenticated.

We can do this easily in a Node.js app.

To make our lives easier, we use the Express web framework to create our HTTP server instead of using the built-in http module.

We also need passport and passport-local to let us add authentication and the body-parser package to parse request bodies.

To install all the packages, we run:

npm install express body-parser passport passport-local

Then we can write the following code to add authentication with passport :

const express = require('express');
const bodyParser = require('body-parser');
const Passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const users = {
  foo: {
    username: 'foo',
    password: 'bar',
    id: 1
  },
  bar: {
    username: 'bar',
    password: 'foo',
    id: 2
  }
}

const localStrategy = new LocalStrategy({
    usernameField: 'username',
    passwordField: 'password'
  },
  function(username, password, done) {
    user = users[username];
    if (user === undefined) {
      return done(null, false, {
        message: 'Invalid user'
      });
    }
    if (user.password !== password) {
      return done(null, false, {
        message: 'Invalid password'
      });
    }
    done(null, user);
  })

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

app.use(express.static('public'));
app.use(Passport.initialize());
Passport.use('local', localStrategy);

app.get('/', (req, res) => {
  res.sendFile('public/index.html');
});

app.post(
  '/login',
  Passport.authenticate('local', {
    session: false
  }),
  function(request, response) {
    response.send('User Id ' + request.user.id);
  }
);

app.listen(3000, () => console.log('server started'));

We require the passport and passport-local packages.

Then we use the LocalStrategy constructor to create our authentication mechanism.

The userField and passwordField are set to the properties of the objects in the users object so that we can get the properties for the username and password.

Then in the function we passed into the 2nd argument of LocalStrategy , we check the user and check the password.

The done fucntion is called to let us return the response message we want depending on the validity of the username or password.

The last done call is run when both the username and password are valid.

Then we call Passport.use to create the 'local' authentication strategy so that we can use the code above with the Passport.authenticate function.

Then we can get the data for the authenticated user with the request.user property.

The data is obtained from calling:

done(null, user);

Now when we make a POST request to the /login route with the request body:

{
    "username": "foo",
    "password": "bar"
}

Then we get:

User Id 1

returned from the server.

If we have a username and password combination that isn’t in the users object, then we get an Unauthorized response body and a 401 status code.

Conclusion

To make adding authentication to our code easier, we can use Passport to let us add the middleware to add basic authentication easier.

Categories
Nodejs

Add Token Authentication to Our Fastify App with fastify-jwt

With the fastify-jwt library, we can add basic authentication to our Fastify app quickly.

In this article, we’ll look at how to use the library to add authentication to our Fastify app.

Installation

We can install the package by running:

npm i fastify-jwt

Issuing Tokens

We can issue tokens by using thee fastify.jwt.sign method.

For example, we can write:

const fastify = require('fastify')({
  logger: true
})
fastify.register(require('fastify-jwt'), {
  secret: 'secret'
})

fastify.post('/signup', (req, reply) => {
  const token = fastify.jwt.sign({ foo: 'bar' })
  reply.send({ token })
})

fastify.listen(3000, '0.0.0.0', function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We just call the method with the object we want as the payload to return a token.

Verify Token

We can verify the token with the jwtVerify method.

For example, we can write:

const fastify = require('fastify')({
  logger: true
})
fastify.register(require('fastify-jwt'), {
  secret: 'secret'
})

fastify.decorate("authenticate", async (request, reply) => {
    try {
      await request.jwtVerify()
    } catch (err) {
      reply.send(err)
    }
  })
  .after(() => {
    fastify.route({
      method: 'GET',
      url: '/secret',
      preHandler: [fastify.authenticate],
      handler: (req, reply) => {
        reply.send('secret')
      }
    })
  })

fastify.post('/signup', (req, reply) => {
  const token = fastify.jwt.sign({
    foo: 'bar'
  })
  reply.send({
    token
  })
})

fastify.listen(3000, '0.0.0.0', function(err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We call the request.jwtVerify method, which is available after we call the fastify.register method.

If there’s an error, the catch block will be run.

To add some routes that require the auth token, we add the after callback with the routes defined by fastify.route .

preHandler runs before the route is called so that we can run the auth token check and call the route handler only if the token is valid.

Cookies

We can put the auth token in the cookies.

For example, we can write:

const fastify = require('fastify')()
const jwt = require('fastify-jwt')

fastify.register(jwt, {
  secret: 'key',
  cookie: {
    cookieName: 'token'
  }
})

fastify
  .register(require('fastify-cookie'))

fastify.get('/cookies', async (request, reply) => {
  const token = await reply.jwtSign({
    name: 'foo',
    role: ['admin', 'spy']
  })

reply
    .setCookie('token', token, {
      domain: '*',
      path: '/',
      secure: true,
      httpOnly: true,
      sameSite: true
    })
    .code(200)
    .send('Cookie sent')
})

fastify.get('/verifycookie', async (request, reply) => {
  try {
    await request.jwtVerify()
    reply.send({ code: 'OK', message: 'it works!' })
  }
  catch(error){
    reply.send(error);
  }
})

fastify.listen(3000, '0.0.0.0', function (err, address) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

We add the /cookies route to issue the cookie.

The setCookie is available after we register the fastify-cookie plugin.

We pass the token into the setCookie method to pass the cookie in the response header.

secure makes sure it’s sent over HTTPS.

httpOnly makes sure it’s only used with HTTP requests.

sameSite checks if the cookie is issued from the same site it’s used in.

In the verifycookie route, we call request.jwtVerify to verify the cookie before doing anything else.

Conclusion

We can use fastify-jwt to issue JSON web tokens and verify it.