This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

hapi.js - Managing State with Cookies

3:05 Node.js lesson by

hapi has built-in support for parsing cookies from a request headers, and writing cookies to a response, making state management easy and straight-forward. It even has built in support for cookie encryption and auto detects when a cookie contains JSON, parsing or stringifying automatically.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

hapi has built-in support for parsing cookies from a request headers, and writing cookies to a response, making state management easy and straight-forward. It even has built in support for cookie encryption and auto detects when a cookie contains JSON, parsing or stringifying automatically.

Avatar
Irvin

Enjoyed the course. Would really like a course building an API application using hapi.js. For example, the proverbial ToDo or Bookstore app, with a Mongo or RethinkDB backend, models, controllers, project structure and tooling. Maybe touch on testing at the end. This would be great!

In reply to egghead.io
Avatar
Alexander Hofstede

+1 What Irvin said ^^ ;)

In reply to Irvin
Avatar
Vincent

+1 to Irvan, would like to be able to produce something useful, not just piece of code that i will have to lose hours trying to figure out how to make it work together

Avatar
Charles

Hi! JSON cookie values aren´t working for me! apparently hapi doesn't serialize/deserialize objects anymore?? (hapi version: ^14.2.0)

//------ index.js ------
server.route(
{
        method: 'GET',
        path: '/cookies',
        handler: (request, reply) => {
          let johnCookie= request.state.charlie
          let resp = reply(`<h1>Cookie <em>${johnCookie}</em> found!</h1>`)

          resp.state('john', {fname: 'john', lname: 'doe', email: 'johndoe@gmail.com'})
        }
})
//------ server nodemon------
Debug: internal, implementation, error
    Error: Invalid cookie value: [object Object]
    at C:\__dirname\node_modules\statehood\lib\index.js:373:38
    at C:\__dirname\node_modules\statehood\lib\index.js:447:20
    at C:\__dirname\node_modules\hoek\lib\index.js:854:22
    at nextTickCallbackWith0Args (node.js:453:9)
    at process._tickDomainCallback (node.js:423:13)
160822/091352.066, [response] http://localhost:8000: get /cookies {} 500 (54ms)

//------ browser response------
{"statusCode":500,"error":"Internal Server Error","message":"An internal server error occurred"}

´´´
In reply to egghead.io
Avatar
yuki

Adding "isSecure:false" option to cookie configuration did the trick! It's true by default and it means it's not available in insecure environment like http.

server.state('id', {
  ttl: 60 * 60 * 1000,
  isHttpOnly: true,
  isSecure: false,
  encoding: 'iron',
  password: 'password'
});
In reply to Charles
Avatar
Domnique

+1 to Irvin!

Hapi's reply method returns a response object, which includes a state method. State can be used to set cookies on a routes response. The first argument is the cookie's name, and the second is the value. For this example, I'll use hello and world.

When I refresh the browser, I've got a cookie named hello with a value of world showing in the resources tab of the dev tools. If I change the value of the cookie and refresh, the change is reflected in the browser.

Now that we've touched on writing cookies, let's take a look at reading them. Hapi automatically parses the requests cookie header, and adds the resulting cookies to the request.state object. I'll read in my hello cookie by assigning request.state.hello to the variable hello. I'll print it in the response, as well.

Now, when I refresh, I see the value mom after the word cookies. That's because the new value of world wasn't set until after the request was finished. It read the previous value, which was mom. Refreshing again gives me world.

Next, let's take a look at how to control the extra properties of the cookie, like its expiration and whether, or not it's flagged as HttpOnly. The state method takes a third options argument. The TTL property is used to control expiration.

I'll set it to expire after 60 minutes, and I'll set isHttpOnly to true, which turns on the cookie's HttpOnly flag. After a refresh, the expiration is set to an hour from now, and the HttpOnly flag is turned on.

Hapi also includes support for encoding and encrypting cookies. I'll add an encoding property here set to iron, and add a password with a long random value. Now when I refresh, the value of my cookie is long and garbled.

If I refresh again, the value of the cookie printed to the page is now garbled, as well. What happened? Hapi doesn't know that I want to use an encrypted cookie when it's parsing the request headers. It just passes along the value that it sees.

Another issue you may have noticed is that I'm setting the cookies options in the route handler. It's quite possible that I may want to use this cookie in more than one route.

Instead of setting the options here, Hapi provides a state method on the server object specifically designed to provide default settings for a given cookie.

The first argument is the cookie name -- hello, in my case -- and the second argument is the cookie's default configuration. Now when I refresh, world once again prints on the page, and the cookie's value is still encrypted.

The last thing I wanted to mention is that Hapi will automatically serialize and deserialize JSON cookie values. If I change the value to an object with a name key, then have my route read the name property off the cookie, and refresh, the value is set. Refresh again to see the value on the page.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?