Demo: Demo: Odin and Friends

Using Express to build a humble catalog of Norse gods and their responsibilities.

Scroll down...

Content

Resources

Comments

For this Demo, we will create a simple website for viewing some of the Norse Gods and their respective traits. We will use our hard-won knowledge of Express to achieve this. Behold!

The Norse Gods

Note to start

At any time you can reference this repo for the full implementation of the application.

A Helpful Generator

While there is no canonical way to organize Express applications, you will often find yourself creating the same folders over and over again. Or perhaps you find yourself creating different folder structures each time. Either way, it can be useful to have some of these decisions taken out of your hands. For this demo, we are going to use the express-generator library to start our app. The generator will create a bunch of the files and also add some default code for you in those files. This reduces the amount of time spent to set things up. Tooling at its best!

Let's get started.

  1. Install the generator with npm.
npm install express-generator -g
  1. Run the express generator, specifying our favorite view engine (Handlebars).
express --view=hbs odin_and_friends
  1. Voila! That's all we'll see of the generator. A couple of things to note here: --view=hbs sets the templating library to Handlebars and odin_and_friends will be the top level name of the folder that will be generated for you. Now we have a nice place to get started from. You have a folder called odin_and_friends and inside a list of helpful files and folders (public, bin, routes, views, package.json, etc.). Feel free to inspect the contents and the code inside and familiarize yourself with the structure before moving on.

Building the Data Module

What would our Norse God database be without some God data? First, we will create a models folder, just to keep things nicely partitioned. In this folder, we'll add a gods.js file. This will simply export a list of gods.

function God(name, domains) {
  this.name = name
  this.domains = domains
}

var gods = [
  new God("Baldur", ["Beauty", "Innocence", "Peace"]),
  new God("Bragi", ["Poetry", "Music", "Harp"]),
  new God("Dagr", ["Daytime", "Talkshows"]),
  new God("Freyja", ["Love", "Fertility", "Battle"]),
  new God("Loki", ["Trickery", "Mischief"]),
  new God("Mimir", ["Object Oriented Programming", "Agile", "Scrum"]),
  new God("Odin", ["War", "Wisdow", "Magic"]),
  new God("Thor", ["Thunder", "Battle"]),
]

module.exports = {
  God,
  gods
}

This data is going to fuel our app's templates.

Routers

The express generator uses an Express object called a Router. This is essentially a middleware function that lets you easily group different routing functions into different files (or different modules, because in Node, a file that exports some functionality is the equivalent of a module). Router will help us define and register different routes inside our application as well as make sure incoming requests are routed to the approapriate functionality. Let's take a look at how we will use a Router to separate a route handling function from our main app.js file.

To accomplish that, let's first write some code in routes/index.js.

// This is in routes/index.js

var express = require('express')

// Here we build the router.
var router = express.Router()
var gods = require('../models/gods').gods

// Notice how we're calling get on the router
// This register the root route (/) and associates a callback as a functionality
// which will be triggered for any incoming request matching this URL
router.get('/', function(req, res, next) {
  res.render('index', { gods: gods })
})

// Finally, we return the router so we can
// use it in our app.js
module.exports = router

Now in app.js we require the code above.

// This is in app.js
var express = require('express')

// And here we go, requiring our router
var index = require('./routes/index')

// And this is how you register the required routes so you can use them
app.use('/', index)

Using a router allowed us to easily pull our get function into a different file. While this application is going to be pretty small, routers are a great organizational tool for larger apps.

Besides the router business, we are requiring our list of gods and passing them down to an index.hbs template.

Enumerating in Handlebars

Let's take a look at our index template.

<h1>Norse Gods</h1>

{{#each gods as |god|}}
  <div class="god">
    <div class="god-name">
      <a href="/gods/{{god.name}}">
         {{god.name}}
       </a>
    </div>

    <div class="god-domains">
      {{#each god.domains as |domain|}}
        <div class="god-domain">
          {{domain}}
        </div>
      {{/each}}
    </div>
  </div>
{{/each}}

Here you can see Handlebars' very helpful each helper. The template within the {{#each .. as |x|}} and {{/each}} will be rendered for each member of the array passed to each. Each item will be assigned to the value within the pipes after the as keyword. All in all, it's quite similar to a forEach function, only with a different syntax.

Now that you understand each, you can see that our index template simply lists each Norse God, with each of their godly domains listed below. There is also a link to an individual god, which will be handled by our god router.

Adding another Router

Let's see what happens when we click on one of these gods. Here is the router.

  var express = require('express');
  var router = express.Router();
  var gods = require('../models/gods').gods
  var God = require('../models/gods').God

  function findGod(name) {
    return gods.find(function(god) {
      return name == god.name
    })
  }

  /* GET home page. */
  router.get('/:name', function(req, res, next) {
    var god = findGod(req.params.name)
    res.render('god', { god: god })
  });

  module.exports = router

This is very similar to our other router, only now we are grabbing a route parameter and passing it into a custom function in order to find the correct god object.

Interestingly, the router's path is relative to the path passed to the app's use function, so we match on /:name here and /gods in our app.js:

var god = require('./routes/god')

// And this is how we register it so we can use it
app.use('/gods', god)

So, "localhost:3000/gods/Odin" would be required to correctly visit the Odin path.

Wrapping Up

Hopefully, seeing one final example of an Express application before you're tasked with creating your own will prove useful. You've been exposed to some new template and middleware tools, along with the useful express-generator. Feel free to inspect the code on the demo repository for a quick reminder. Now it's time to test thyself before you take on the assignment.

Octocat 300


Sign up to track your progress for free

There are ( ) additional resources for this lesson. Check them out!

There are no additional resources for this lesson just yet!

Sorry, comments aren't active just yet!

Next Lesson: Test Yourself: Express