JavaScript joelf Node.js Okta sponsored Tech

Build Your First Router in Node with Express — SitePoint

File Server Demo

This text was initially revealed on the Okta developer weblog. Thanks for supporting the companions who make SitePoint attainable.

When you’ve achieved any net improvement with Node in the previous few years, you’ve in all probability used Express. Even for those who haven’t used it immediately, many frameworks meant to make net improvement even easier are nonetheless constructed on Express.

One of many key options in Express is the power to create routes. An infinite mixture of URLs can hit the identical Express server, and routes are how one can decide which URLs run what piece of code. You’ll be able to have parameters and wildcards so that you simply don’t need to explicitly state every endpoint.

On this tutorial, I’ll stroll you thru making a server and train you all it is advisable find out about routes in Express.

What’s a Route in Express?

Routes decide what knowledge ought to be delivered given any URL. Let’s take probably the most primary file server for instance. Say you have got a file construction of:

information/
├── photographs/
│ ├── cat.png
│ ├── canine.jpg
│ └── pig.bmp
└── textual content/
├── README.md
└── todo.txt

You would then run a easy HTTP server that may mechanically serve these information and create an index for the directories. There’s no information/index.html, however the server continues to be producing an internet web page and serving up content material based mostly on the information in that folder. When you go to /photographs/cow.gif you’ll get a 404 error – regardless that there’s no file there, it’s nonetheless serving up one thing.

npm set up -g http-server
cd information
http-server

File Server Demo

In Express, a route consists of a way, a path, and a handler.

Strategies, Paths, and Handlers, Oh My!

The tactic could possibly be any HTTP verb, resembling GET (for fetching content material – that is what most net pages use), or POST (for sending content material to the server – that is widespread with HTML types). You may as well specify that you really want Express to deal with the identical path for all strategies in the event you select.

The trail is a string or a daily expression that describes the relative URL. When you’re working with the basis of your app, this describes absolutely the URL. A path might be outlined in a couple of methods.

  • Easy Strings: A string of ‘/’ specifies that you simply need to use this route on the root of your router. A string of ‘/asdf’ would cowl the trail /asdf
  • Wildcards: The string also can include a number of wildcards, which work just like a daily expression, however are a bit restricted:
    • ?: A ? says that the earlier character is optionally available. The trail ‘/Joh?n’ would cowl each /Jon and /John
    • +: A + says that the earlier character may be repeated as many occasions as you want, however needs to be a minimum of as soon as. A path of ‘/ni+ce’ would cowl /good in addition to /niiiiiiiiiiiiiiiiice
    • *: A * says that the earlier character is elective and may be repeated as typically as you want. A path of ‘/wow!*’ would match /wow, /wow!, and even /wow!!!!!!!!!!!!
    • (): You can even apply wildcards to a gaggle of characters. ‘/(ha)+’ would match /ha, /haha, and /hahahahaha, however not /hah
  • Common Expressions: If you wish to transcend primary wildcards, you’ll be able to go nuts with a daily expression. With /^/(pen-)?((pine)?apple-)+pen$/ you may match /apple-pen, /pineapple-pen, or /pen-pineapple-apple-pen.
  • Parameters: One other very helpful function, is you’ll be able to have parameters in your route. This allows you to simply present RESTful URLs with dynamic parts. A path of ‘/posts/:postId’ won’t solely match /posts/42, however the request will include a params.postId variable with a worth of ’42’.

The tactic and path are important to know when to do one thing, however the handler is the callback perform that really will get referred to as in these instances. A handler is handed a request, a response, and a subsequent callback, and people arguments are sometimes written as (req, res, subsequent)..

  • Request (req): The request incorporates all types of details about what’s been requested by the consumer. From right here you’ll be able to entry the trail, parameters, headers, and a myriad of different issues. For all the things on a request, you possibly can seek the advice of the API reference
  • Response (res): The response is the way you ship info again to the consumer. The only solution to ship again knowledge is with the .ship technique (e.g. res.ship(‘Hey, world!’)), however there are numerous different strategies. Once more, you will discover all of the strategies in the API reference
  • Subsequent Callback (subsequent): The subsequent perform permits you to use a number of handlers for a similar route. You should use one handler to course of info, and when it’s accomplished it will probably name subsequent() to sign it’s OK to maneuver on to the subsequent handler. When you move in a string, it can as an alternative throw an error, which you’ll be able to catch elsewhere, or show to the consumer (e.g. subsequent(‘You have to be authenticated to entry this route’)).

What’s a Router in Express?

Now that you simply’re a bit of extra acquainted with routes, how is that totally different from a router? You possibly can consider a router as a set of routes. This is usually a helpful strategy to manage totally different sections of your app.

When utilizing a router, you’ll be able to assume in phrases of a root path, even in case you’re going to be utilizing that router from some subpath. For instance, say you could have an API to handle messages. You might have a router with a path ‘/’ to GET all messages or POST a brand new message. You possibly can have one other path ‘/:id’ to GET or PUT (edit) a selected message.

Your app might then take that router and host it at /messages, with app.use(‘/messages’, messageRouter). The router itself doesn’t should care what its international path goes to be, and may even be used in a number of routes (e.g. /messages, /texts, and /e mail).

Create a Easy App with a Router in Node with Express

Sufficient speak already… let’s get to some actual code. To get began, create a folder that may home all of your code. Then arrange a package deal.json folder to assist handle dependencies. You need to use npm init to do that. You’ll additionally want to put in Express.

mkdir my-first-router
cd my-first-router
npm init -y
npm set up categorical@four.16.four hbs@four.zero.1

Create an index.js file with the next code:

index.js

const categorical = require(‘categorical’)
const path = require(‘path’)

const app = categorical()

app.set(‘views’, path.be a part of(__dirname, ‘views’))
app.set(‘view engine’, ‘hbs’)

app.get(‘/’, (req, res) =>
res.render(‘index’,
title: ‘Whats up, world!’,
content material: ‘How are you?’
)
)

const port = course of.env.PORT || 3000
app.pay attention(port, () => console.log(`App listening on port $port`))

This tells Express to make use of Handlebars (hbs) as a view engine. It makes use of Node’s built-in path to inform it the listing containing the views. The / path is advised to render the web page utilizing index.hbs, which can put the content material in a paragraph (p) tag.

To ensure Express has templates to render, create a brand new folder referred to as views, then create a brand new file in there referred to as format.hbs. If you inform Express to render a view, it’ll first render format.hbs and put the content material of the view contained in the physique tag. This allows you to arrange a skeleton for the app. Right here’s some primary HTML utilizing Bootstrap that offers you some good styling while not having to put in writing any CSS. This will even render the title handed into the context in your / route.

views/format.hbs

<!doctype html>
<html lang=”en”>
<head>
<!– Required meta tags –>
<meta charset=”utf-8″>
<meta identify=”viewport” content material=”width=device-width, initial-scale=1, shrink-to-fit=no”>

<!– Bootstrap CSS –>
<hyperlink rel=”stylesheet” href=”https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css” integrity=”sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO” crossorigin=”anonymous”>

<title>title</title>
</head>
<physique>
<h1>title</h1>
<most important>
physique
</foremost>
</physique>
</html>

You’ll additionally have to create a index.hbs view that may simply be actually primary for now:

views/index.hbs

<p>content material</p>

To make improvement a bit of simpler, you possibly can set up nodemon with:

npm set up –save-dev nodemon@1.18.four

Then modify your package deal.json file in order that the “scripts” entry features a begin script with nodemon .. It will make it to be able to merely run npm begin and your server will mechanically restart everytime you make modifications:

“scripts”:
“start”: “nodemon .”

Now in your terminal, when you sort npm begin you’ll begin the server. You possibly can then go to http://localhost:3000 to see the app operating.

File Server Demo

Create a Router in Express

Properly, that’s sort of boring. How about making it do one thing helpful? Let’s create a easy to-do record. Begin by making a router to handle an inventory of things. Make a brand new file referred to as todo.js:

todo.js

const categorical = require(‘categorical’)

const router = categorical.Router()

let todo = []

router.submit(‘/’, (req, res, subsequent) =>
todo = […req.physique.todo || []]
if (req.physique.take away) todo.splice(req.physique.take away, 1)
if (req.physique.new) todo.push()

subsequent()
)

router.use(‘/’, (req, res) =>
res.render(‘todo’, title: ‘To-do listing’, todo )
)

module.exports = router

Right here you could have two route handlers. The primary one listens for POST requests (signified by router.publish). It is going to substitute the to-do record with a replica of no matter it receives from the shape. If the shape incorporates the take away property (containing an index), it can use splice to take away the aspect at that index. If the shape incorporates the brand new property, a brand new merchandise might be pushed on to the array. After it’s executed modifying the to-do record, it calls subsequent() to maneuver on to the subsequent route handler.

The second route handler is all the time used (signified by router.use). Its sole function is to render the to-do listing. By separating the routes like this, you possibly can simply do one factor all the time, and one other factor solely in sure circumstances (in this case on a POST request).

To inform the app to make use of this router, you’ll have so as to add a couple of strains to index.js:

index.js

@@ -1,11 +1,15 @@
const categorical = require(‘categorical’)
const path = require(‘path’)
+const todoRouter = require(‘./todo’)

const app = categorical()

app.set(‘views’, path.be a part of(__dirname, ‘views’))
app.set(‘view engine’, ‘hbs’)

+app.use(categorical.urlencoded( prolonged: true ))
+app.use(‘/todo’, todoRouter)
+
app.get(‘/’, (req, res) =>
res.render(‘index’,
title: ‘Whats up, world!’,

Now for the todo template. It’s slightly bigger, so I saved it for final. In case you’re acquainted with HTML it shouldn’t be too dangerous to comply with. Handlebars provides a couple of options that allow you to entry variables. On this case, you’re utilizing an #if block to render one thing particular if there aren’t any gadgets, in addition to an #every block to render every of the listing gadgets with minimal markup.

The one JavaScript used right here is for mechanically submitting the shape whenever you change one thing. If JavaScript have been disabled, this might nonetheless work when urgent the “Enter” key in your keyboard, because of the hidden button labeled “Autosave”.

views/todo.hbs

<type technique=”post”>
<div class=”row”>
<div class=”col”>
<button hidden>Autosave</button>
<button class=”btn btn-success” identify=”new” worth=”true”>New</button>
</div>
</div>
<div class=”row mt-3″>
<div class=”col”>
#if todo.size
<ul class=”list-group”>
#every todo
<li class=”list-group-item d-flex align-items-center”>
<enter
sort=”checkbox”
onchange=”this.form.submit()”
identify=”todo[@index][checked]”
#if this.checkedchecked/if
/>
<enter
identify=”todo[@index][text]”
onchange=”this.form.submit()”
class=”form-control mx-2″
worth=”this.text”
/>
<button class=”btn btn-danger” identify=”remove” worth=”@index”>Take away</button>
</li>
/every
</ul>
else
<h5>Your To-Do Record is empty</h5>
/if
</div>
</div>
<fashion>
enter[type=checkbox]:checked + enter
text-decoration: line-through;
opacity: zero.75;

</type>
</type>

Now go to http://localhost:3000/todo and enter some gadgets into your todo record.

Buy Milk

Add Consumer Authentication in Node

Now you’ve gotten a useful to-do record. You’ll have observed although, this might solely work if you would like everybody utilizing it to share the identical listing. For those who add in authentication, you possibly can have a separate to-do listing for every consumer.

Including customers doesn’t should be a ache. Actually, it may be carried out actually merely with Okta. What’s Okta?, you may ask. Okta is a cloud service that permits builders to create, edit, and securely retailer consumer accounts and consumer account knowledge, and join them with one or a number of purposes.

When you don’t have already got one, join a forever-free developer account.

You’re going to wish to avoid wasting info to make use of in the app. Create a brand new file named .env. In it, enter your group URL.

HOST_URL=http://localhost:3000
OKTA_ORG_URL=https://yourOktaOrgUrl

Additionally, you will want a random string to make use of as an App Secret for periods. You possibly can generate this with the next instructions:

echo -e “nAPP_SECRET=`npx -q uuid`” >> .env

Subsequent, log in to your developer console, navigate to Purposes, then click on Add Software. Choose Net, then click on Subsequent. Give your software a reputation, like “My First Router”. Change the Base URI to http://localhost:3000/ and the Login redirect URI to http://localhost:3000/authorization-code/callback, then click on Carried out

Click on Edit and add a Logout redirect URI of http://localhost:3000/, then click on Save.

Okta application settings

The web page you come to after creating an software has some extra info you could save to your .env file. Copy in the shopper ID and shopper secret.

OKTA_CLIENT_ID=yourClientId
OKTA_CLIENT_SECRET=yourClientSecret

Now again to the code. You’ll want so as to add Okta’s OIDC middleware to regulate authentication. It additionally depends on utilizing periods. You’ll want to make use of dotenv to learn in variables from the .env file. To put in the dependencies you’ll want, run this command:

npm set up @okta/oidc-middleware@1.zero.1 dotenv@6.1.zero express-session@1.15.6

Now modify your index.js file. Right here you’ll be including the session and OIDC middlewares, and a logout route so customers can sign off of the app. You’re additionally including a middleware particularly to the todoRouter (app.use(‘/todo’, oidc.ensureAuthenticated(), todoRouter)). By including oidc.ensureAuthenticated(), you’re letting Okta ensure that route can’t be reached until a consumer is logged in. If the consumer isn’t logged in and tries to succeed in that route, they’ll be taken to a safe website to log in, and redirected again to your website afterward.

index.js

@@ -1,14 +1,46 @@
+require(‘dotenv’).config()
+
const categorical = require(‘categorical’)
const path = require(‘path’)
+const session = require(‘express-session’)
+const ExpressOIDC = require(‘@okta/oidc-middleware’)
+
const todoRouter = require(‘./todo’)

+const oidc = new ExpressOIDC(
+ issuer: `$course of.env.OKTA_ORG_URL/oauth2/default`,
+ client_id: course of.env.OKTA_CLIENT_ID,
+ client_secret: course of.env.OKTA_CLIENT_SECRET,
+ redirect_uri: `$course of.env.HOST_URL/authorization-code/callback`,
+ scope: ‘openid profile’
+)
+
const app = categorical()

+app.use(session(
+ secret: course of.env.APP_SECRET,
+ resave: true,
+ saveUninitialized: false
+))
+app.use(oidc.router)
+
app.set(‘views’, path.be a part of(__dirname, ‘views’))
app.set(‘view engine’, ‘hbs’)

app.use(categorical.urlencoded( prolonged: true ))
-app.use(‘/todo’, todoRouter)
+app.use(‘/todo’, oidc.ensureAuthenticated(), todoRouter)
+
+app.get(‘/logout’, (req, res) =>
+ if (req.userContext)
+ const idToken = req.userContext.tokens.id_token
+ const to = encodeURI(course of.env.HOST_URL)
+ const params = `id_token_hint=$idToken&post_logout_redirect_uri=$to`
+ req.logout()
+ res.redirect(`$course of.env.OKTA_ORG_URL/oauth2/default/v1/logout?$params`)
+ else
+ res.redirect(‘/’)
+
+)

app.get(‘/’, (req, res) =>
res.render(‘index’,

To make issues a bit of simpler when a consumer logs out, add a hyperlink to the to-do record from the house web page.

views/index.hbs

<p>content material</p>
<a href=”http://www.sitepoint.com/todo”>Go to To-Do Record</a>

It’s also possible to add a welcome message and a sign off button to your format.hbs.

views/format.hbs

@@ -12,6 +12,12 @@
</head>
<physique class=”container”>
<h1>title</h1>
+ #if userinfo
+ <h4>
+ Welcome again, userinfo.given_name!
+ <small><a href=”http://www.sitepoint.com/logout”>Click on right here to sign off</a></small>
+ </h4>
+ /if
<foremost>
physique
</foremost>

For that to work, you’ll want so as to add userinfo to the context when rendering views.

todo.js

— a/todo.js
+++ b/todo.js
@@ -13,7 +13,7 @@ router.submit(‘/’, (req, res, subsequent) =>
)

router.use(‘/’, (req, res) =>
– res.render(‘todo’, title: ‘To-do listing’, todo )
+ res.render(‘todo’, title: ‘To-do record’, todo, userinfo: req.userContext.userinfo )
)

module.exports = router

index.js

@@ -43,7 +43,10 @@ app.get(‘/logout’, (req, res) =>
)

app.get(‘/’, (req, res) =>
+ const userinfo = req.userContext ||
+
res.render(‘index’,
+ userinfo,
title: ‘Hiya, world!’,
content material: ‘How are you?’
)

OK, so now you’re requiring customers to log in earlier than they will edit the to-do record, however it’s nonetheless a single, shared record. So as to cut up it up right into a separate record for every consumer, make one other small change to todo.js.

todo.js

@@ -2,17 +2,21 @@ const categorical = require(‘categorical’)

const router = categorical.Router()

-let todo = []
+const todosByUser =

router.publish(‘/’, (req, res, subsequent) =>
– todo = […req.physique.todo || []]
+ const todo = […req.physique.todo || []]
if (req.physique.take away) todo.splice(req.physique.take away, 1)
if (req.physique.new) todo.push()

+ todosByUser[req.userContext.userinfo.sub] = todo
+
subsequent()
)

router.use(‘/’, (req, res) =>
+ const todo = todosByUser[req.userContext.userinfo.sub] || []
+
res.render(‘todo’, title: ‘To-do listing’, todo, userinfo: req.userContext.userinfo )
)

Multi-User Demo

Study Extra about Node, Express, and Safe Net Improvement

Now that you’ve a totally practical to-do listing, I encourage you to broaden on it. Attempt storing the info in a database, and even let Okta retailer it for you! See when you can create some extra routers so as to add to the online server.

If you wish to see the ultimate code pattern, yow will discover it on GitHub.

Should you’d wish to study extra about Node and Express take a look at a few of these different articles on the Okta developer weblog:

When you have any questions on this publish, please add a remark under. For extra superior content material, comply with @oktadev on Twitter, like us on Fb, or subscribe to our YouTube channel.