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

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.

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. But now we have a nice place to get started from.

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.

class God {
  constructor(name, ...domains) {
    this.name = name
    this.domains = domains
  }
}

const 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 a different module. Let's take a look at how we will use a Router to separate a route handling function from our main app.js file.

// routes/index.js

var express = require('express')

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

// Notice how we're calling get on the router
// rather than on the application
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



// app.js
var express = require('express')

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

// ...

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.

The Other 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();
  const {God, gods} = require('../models/gods')

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

  /* GET home page. */
  router.get('/:name', function(req, res, next) {
    const 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')

// ...

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. 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