Joseph Jude

Consult . Code . Coach

In-depth guide to handling routes in hapijs


code . nodejs . hapijs . tsc

This post is part of Learn to build web-applications with Hapi and Typescript

The web works based on URLs. Take stackoverflow for example. stackoverflow.com takes us to the homepage, stackoverflow.com/questions takes us to the questions page, stackoverflow.com/users takes us to the users page, and so on.

In hapi, server.route determines how a web-app should handle urls typed by a user. In this post, let us understand the elements of server.route.

Let us start with the basic hello world program we wrote in the first post.

"use strict";

import * as hapi from "hapi";

const server: hapi.Server = new hapi.Server()
server.connection({ port: 3000 });

server.route({
    method: "GET",
    path: "/",
    handler: (request: hapi.Request, reply: hapi.IReply) => {
        reply("Hello World")
    }

});

server.start((err) => {
    if (err) {
        throw err;
    }
    console.log("server running at 3000");
)

Here, server.route defines a route to handle the / url. There are three elements we see in this route: method, path, and handler. Let us understand these three elements in detail.

Route Methods

Every http request contains a method. It will be one of GET, POST, PUT, or DELETE. There are other methods too, but for our discussion, we will limit to these methods. Below table explains these methods with an example.

methodUsageExample
GETRetrieve a resource or collection of resourcesGET /users
GET /users/1
POSTCreate a new resourcePOST /users
PUTUpdate a resourcePUT /users/1
DELETEDelete a resourceDELETE /users/1

Let us see how we can define these methods in hapi.

server.route({
    method: "GET",
    path: "/",
    handler: (request: hapi.Request, reply: hapi.IReply) => {
        reply("This is a GET method")
    }

server.route({
    method: "POST",
    path: "/",
    handler: (request: hapi.Request, reply: hapi.IReply) => {
        reply("This is a POST method")

Here, we are handling each http method in its own server.route method. This is easy to read and understand.

We can also handle multiple http methods in a single route.

server.route({
    method: ["GET","POST"],
    path: "/",
    handler: (request: hapi.Request, reply: hapi.IReply) => {
        reply("Got " + request.method + " method");

This is handy to handle a form on the front-end. We can display the form with GET and handle the input with POST using the same handler.

Path Parameters

Path indicates the resource accessed. In the Stackoverflow example we considered, /, /questions, and /users are three different paths. A path can be split into segments. / in a path splits a path into individual segments.

In,

/questions/5

questions and 5 are individual segemetns.

In,

/users/jjude/questions/5

users, jjude, questions, and 5 are individual segments.

These segements will be identified by names. So within hapi route method, these path will be handled as:

/questions/{id}

and,

/users/{username}/questions/{questionId}

Within server.route, these parameters are accessed with the names mentioned in the path. So the code will look like this (notice request.params.id):

server.route({
    method: "GET",
  path: "/questions/{id}",
    handler: (request: hapi.Request, reply: hapi.IReply) => {
        reply("Question requested is: " + request.params.id);
    }
});

If there are multiple parameters in a path, each parameter can be accessed with its name.

server.route({
    method: "GET",
  path: "/users/{userid}/questions/{questionid}",
    handler: (request: hapi.Request, reply: hapi.IReply) => {
        reply("user id requested is: " + request.params.userid + " and question id is: " + request.params.questionid + " ");
    }
});

Optional parameters

Hapi supports optional parameters in the path. We can use optional parameters to define a single route to fetch both a single resource and its collection. Optional parameters are indicated by appending a ? to its name.

server.route({
    method: "GET",
  path: "/users/{userid?}",
    handler: (request: hapi.Request, reply: hapi.IReply) => {
        if (request.params.userid) {
      return reply("user id is: " + request.params.userid);
    } else {
      return reply ("will show user collection");
    }
    }
});

Optional parameter can appear only as a last parameter.

Wildcard parameters

If we want to repeat a segment, we can use * followed by a number. Say, we are running a blog and want to repeat the category twice. Then the path will be,/{category*2}.

We can split the segment to get the individual segments. For example, request.params.category.split('/') will get us the individual segment.

We can also omit the number to match unlimited segments. This is called catch-all route since they handle routes that are not handled by specific routes. They are useful in implementing 404 pages.

Route handlers

Handler function accepts two parameters: request and reply.

The request parameter contains headers, authentication information, payloads and others. The reply parameter is used to respond to the requests. Usually it only contains payload. But it can also have headers, content types, content length and so on. It can be chained to indicate the response code too. For example, reply('not found').code(404).

Conclusion

Routes help us to add functionality to our web-apps. Understanding them is critical to develop hapijs applications.

Got questions? Ask in comments or via twitter

Interested in learning hapi with typescript? Subscribe now, using the below form, to receive each new lesson for free.


Like the post? Retweet it. Got comments? Reply.

In-depth guide to @hapijs routes by @jjude: https://t.co/QbwjCYqVKn

— Joseph Jude (@jjude) February 16, 2017
Share this on: Twitter / /

Comments

comments powered by Disqus