Introduction to APIs
Image source : Wikibon > An API is a set of functions and procedures that allow the creation of applications which access the features or data of an operating system, application, or other service — Google
An Application Programming Interface (API) is a set of subroutine definitions, protocols, and tools for building application software… — Wikipedia
These definitions are combinations of multiple unfamiliar terms which seem like nonsense and scary at first. You can spend a whole day trying to look up every term above and forget what you were searching for in the first place and the chain just never ends.
This happens to everyone. What you should never do is give up. We are here to discuss APIs in a less scary way, let’s get started!
To Do:
- Explain what an API is.
- Discuss why you would build an API.
- Build a simple app using the Auth0 API.
The magnificent, “Application Programming Interface” or API, highly exalted in the previous definitions above is simply a messenger. Think of an API as a waiter. You go to your favorite classy restaurant to buy food, you have to place your order ( make a request ) right? Someone walks up to you with list of meals available, the waiter ( API ) . The waiter takes your order, goes to the kitchen to process your order and comes back with the meal.
How requests were made before APIs
Take a look at cheap restaurants, where there are no waiters, no menu, you just walk straight to the kitchen to get your meal. I believe you know how messy and inconvenient that can get, lots of customers barking their orders, each struggling to get attention. You don’t want to be caught up in that mess.
Well, before APIs, clients interacted with the data store directly, which had lots of downsides to it; the biggest of which was the lack of security.
In computing, APIs take the request from the user of an app (web client, mobile app, etc.) to get or send a resource. Say you just placed an order for a MacBook from an online store. The online store's API takes the order information and sends it to the server to process the order, then returns a response, notifying you whether it was successful or not. The data has to be represented in a format that both the app and the server will understand, just the way the menu is written in a specific language you and the waiter understand so he can place the right order for you at the kitchen. The generally accepted format is JSON (JavaScript Object Notation). The order information may look like this:
{ "customerName" : "John Doe", "item" : "MacBook Pro", "price" : 1000 }
The API (messenger) sends this data to the Data Store, which saves the order information and API returns with response for the Client. Example response :
{ "status": true, "message": "Your order has been successfully placed, kindly anticipate delivery in couple days" }
Upon receipt of this response, the client app traverses the data to fetch the needed info. The user gets to see only this message, others are abstracted.
Why do you need an API?
Let’s say you want to display motivational quotes on a section of your website. You might decide to write all these quotes or copy them off the internet and save them in your database. But don’t forget you need a sufficient amount of these, you don’t want to bore your readers with same quotes all the time. So imagine the stress of getting these quotes and saving everything in the database.
Image source: The Bitchy Waiter
APIs are accessed though endpoints. Endpoints present an interface via which a resource or group of resources can be accessed. So when a request hits the API, it knows just what you want and how to respond to the call. Take a look at these endpoints from talaikis.com :
Endpoints available:
- https://talaikis.com/api/quotes/random — returns one random Quote.
- https://talaikis.com/api/quotes — returns 100 random quotes at a time.
From the code above, calls made to those endpoints return different resources. The first returns a random quote every time it’s called, while the other returns 100 random quotes. For your app, I believe the first endpoint is just perfect, so we'll use it!
NOTE: Before you can make use of any API, you have to read the documentation, know the type of request it takes, queries, parameters and the structure of the expected response.
A sample request using
method to call the first endpoint:jQuery.getJSON()
jQuery.getJSON('https://talaikis.com/api/quotes/random/', function(quote){ //code to display your quote on the website goes here. })
Response:
{ "quote": "I'd like to talk about free markets. Information in the computer age is the last genuine free market left on earth except those free markets where indigenous people are still surviving. And that's basically becoming limited.", "author": "Russell Means", "cat": "age" }
Does that look familiar? Yea, that’s JSON again. We've used a simple external API to get the data we needed with ease.
There’s a lot more we can do with the API, but that’s all we will cover for now. Next, let's build a full application that utilizes various APIs to get a feel of how to work with them.
Quotes Web App
To Do:
- Build a Quotes Application.
- Introduce Auth0.
- Use Auth0 for User Authentication in our application.
Building a Quotes Application with ExpressJS
This session assumes you know basic Node.js & Express framework, if not take time out to read up here
Create an ExpressJS (a framework built on top of Node) project using express-generator. Run the commands below to setup express and create a new project.
$ npm install -g express-generator $ express quotesGenerator $ cd quotesGenerator
The second command creates a folder and basic files to start up your project. Open the folder with your favorite IDE or text editor.
Run the command below to install the dependencies described in
package.json
.$ npm install
Install additional dependencies:
$ npm install connect-flash express-session passport hbs --save
- connect-flash stores flash messages in the session.
- express-session is a nodejs middleware for handling sessions.
- passport is an authentication middleware for nodejs
- hbs is a templating engine for nodejs.
Open up
app.js
and make the following changes:app.js
//require the modules const passport = require('passport'); const session = require('express-session'); const flash = require('connect-flash'); // set up hbs for templating app.set('view engine', 'hbs'); //Replace the line below app.use(cookieParser()) with the code below; //required for passport to maintain user state/data. app.use( session({ secret: 'APP_SECRET', resave: true, saveUninitialized: true }) ); app.use(passport.initialize()) //initialize passport app.use(passport.session()); // persistent login sessions app.use(flash()); // use connect-flash for flash messages stored in session //set static files / assets directory app.use(express.static(path.join(__dirname, 'public'))); // Handle authentication failure error messages app.use(function(req, res, next) { if (req && req.query && req.query.error) { req.flash("error", req.query.error); } if (req && req.query && req.query.error_description) { req.flash("error_description", req.query.error_description); } next(); }); // Check logged in app.use(function(req, res, next) { res.locals.loggedIn = false; if (req.session.passport && typeof req.session.passport.user != 'undefined') { res.locals.loggedIn = true; } next(); });
Next thing is to create the views:
- Index.hbs
- Profile.hbs
- error.hbs
- layout.hbs
Create those files inside your view directory and rename any
.jade
file to .hbs
.views/error.hbs
<h2>{{message}}</h2> <h2>{{error.message}}</h2> <pre>{{error.stack}}</pre>
The file above display errors while developing with stack traces. The double curly braces allows us to get variables passed from the server-side, you will be seeing more of it.
views/layout.hbs
<html> <head> <title> {{title}} </title> <!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <!-- Latest compiled and minified jQuery --> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <!-- Latest compiled and minified JavaScript --> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/">Quotes Generator</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="/">Home <span class="sr-only">(current)</span></a></li> <li><a href="/user">Profile</a></li> </ul> <ul class="nav navbar-nav navbar-right"> <li><a href="/logout">Logout</a></li> </ul> </div> <!-- /.navbar-collapse --> </div> <!-- /.container-fluid --> </nav> <div class="container" style="margin-top:40px"> {{{ body }}} </div> </body> </html>
This is a parent view every other view file will have to inherit from. I have included the required assets we need; bootstrap.min.css, jquery.min.js, bootstrap.min.js.
views/index.hbs
<h1>Famous Quotes</h1> <blockquote> <p id="quoteBody">Fetching...</p> <footer id="quoteAuthor"></footer> </blockquote> <script> //ensure the page has completely loaded $(document).ready(function(){ //send a get request to get random quote once page loads jQuery.getJSON('https://talaikis.com/api/quotes/random', function(data){ //update the view with the quote $('#quoteBody').text(data.quote) $('#quoteAuthor').text(data.author) }) }) </script>
This is the landing page. It displays random post everytime it’s loaded. The tiny script embedded in it calls the talaikis.com quotes api to obtain random quote.
views/profile.hbs
<div class="col-sm-4 col-sm-offset-4" style="margin-top:100px"> <div class="panel panel-info"> <div class="panel-heading"> <h2>Short Bio</h2> </div> <div class="panel-body"> <img src="{{ user.picture }}" class="img-circle img-responsive" alt="profile-pic"/> <h2>Name : <span> {{ user.displayName }} </span> </h2> <h2>Nickname : <span> {{ user.nickname }}</span></h2> <h2>Gender : <span> {{ user.gender }} </span> </h2> </div> </div> </div>
Run the App
Start up your server if it’s not running.
$ npm start
landing page
profile page
That's all we have for now but let's be a little stingy with access to the quotes. Users should have to log in to see them. This is where Auth0 comes in.
What is Auth0?
Auth0 issues JSON Web Tokens on every login for your users. This means that you can have a solid identity infrastructure, including single sign-on, user management, support for social identity providers (Facebook, Github, Twitter, etc.), enterprise identity providers (Active Directory, LDAP, SAML, etc.) and your own database of users with just a few lines of code. If you don't already have an Auth0 account, sign up for one now."
On your dashboard, create a new client, a client is simply the app we want to manage.
Give it a name and select “Regular Web Application (with refresh)”.
Next, choose the technology for the project, which in our case is Node.js. Navigate to the settings tab, take note of your domain, client id and client secret.
Step 1: Install the Middleware Dependencies
Make sure you are in the root directory of the project, then run the command:
$ npm install passport-auth0 connect-ensure-login --save
- passport-auth0 is a nodejs Auth0 package using passport.
- connect-ensure-login middleware ensures that a user is logged in.
Step 2: Configure the Middlewares
Create a new instance of the Auth0Strategy strategy. Enter your Auth0 client details as configuration values. Tell passport to use the strategy.
Update the app.js file to include this configuration.
app.js
//requiring dependencies //Auth0 aunentication configuration const Auth0Strategy = require('passport-auth0'); // Configure Passport to use Auth0 const strategy = new Auth0Strategy( { domain: 'YOUR_DOMAIN', clientID: 'YOUR_CLIENT_ID', clientSecret: 'YOUR_CLIENT_SECRET', callbackURL: 'http://localhost:3000/callback' }, (accessToken, refreshToken, extraParams, profile, done) => { return done(null, profile); } ); passport.use(strategy); // This can be used to keep a smaller payload passport.serializeUser(function(user, done) { done(null, user); }); passport.deserializeUser(function(user, done) { done(null, user); });
Place this snippet just above the part where we set the view engine.
Replace the placeholder values with the credentials on your dashboard. I recommend that you load them from environment variables to prevent your credentials from been leaked. Make sure your
app.js
file looks like this.Step 3: Configure the Callback URL
Head over to your Auth0 dashboard and register a callback url in Allowed Callback URLs like this:
localhost:3000/callback
Replace the content of
index.js
file in routes folder with this:routes/index.js
const express = require('express'); const passport = require('passport'); const router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.render('index'); }); // Perform the login router.get( '/login', passport.authenticate('auth0', { clientID: 'YOUR_CLIENT_ID', domain: 'YOUR_DOMAIN', redirectUri: 'http://localhost:3000/callback', audience: 'https://' + 'YOUR_DOMAIN' + '/userinfo', responseType: 'code', scope: 'openid profile' }), function(req, res) { res.redirect('/'); } ); // Perform session logout and redirect to homepage router.get('/logout', (req, res) => { req.logout(); res.redirect('/'); }); // Perform the final stage of authentication and redirect to '/users' router.get( '/callback', passport.authenticate('auth0', { failureRedirect: '/' }), function(req, res) { res.redirect('/'); } );
Open
users.js
, let’s modify that to send the data of a logged in user to the view.users.js
const express = require('express'); const passport = require('passport'); const ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn(); const router = express.Router(); /* GET user profile. */ router.get('/', ensureLoggedIn, function(req, res, next) { //req.user holds the details of authenticated user //render profile.hbs with the user data res.render('profile',{ user: req.user }); }); module.exports = router;
Modify
profile.hbs
to use data provided by the route above.views/profile.hbs
<div class="col-sm-4 col-sm-offset-4" style="margin-top:100px"> <div class="panel panel-info"> <div class="panel-heading"> <h2>Short Bio</h2> </div> <div class="panel-body"> <img src="{{ user.picture }}" class="img-circle img-responsive" alt="profile-pic"/> <h2>Name : <span> {{ user.displayName }} </span> </h2> <h2>Nickname : <span> {{ user.nickname }}</span></h2> <h2>Gender : <span> {{ user.gender }} </span> </h2> </div> </div> </div>
You will notice that I have replaced the hardcoded names with the user details rendered with the view.
Add a check to
index.hbs
to ensure user is logged in before they can see the quotes using the connect-ensure-login
.views/index.hbs
{{#if loggedIn }} <h1>Famous Quotes</h1> <blockquote> <p id="quoteBody">Fetching...</p> <footer id="quoteAuthor"></footer> </blockquote> {{else}} <div class="alert alert-danger"> <h3> Kindly login to see the amazing quotes</h3> <h4>Please <a href="/login"> Log In</a> to continue.</h4> </div> {{/if}} <script> //ensure the page has completely loaded $(document).ready(function(){ //send a get request to get random quote once page loads jQuery.getJSON('https://talaikis.com/api/quotes/random', function(data){ //update the view with the quote $('#quoteBody').text(data.quote) $('#quoteAuthor').text(data.author) }) }) </script>
Let’s update layout.hbs to toggle the login/logout based on the user’s logged in state.
layout.hbs
<html> <head> <title> {{title}} </title> <!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <!-- Latest compiled and minified jQuery --> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <!-- Latest compiled and minified JavaScript --> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/">Quotes Generator</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="/">Home <span class="sr-only">(current)</span></a></li> <li><a href="/user">Profile</a></li> </ul> <ul class="nav navbar-nav navbar-right"> {{#if loggedIn}} <li><a href="/logout">Logout</a></li> {{else}} <li><a href="/login">Login</a></li> {{/if}} </ul> </div> <!-- /.navbar-collapse --> </div> <!-- /.container-fluid --> </nav> <div class="container" style="margin-top:40px"> {{{ body }}} </div> </body> </html>
Run the App
localhost:3000
localhost:3000/login
localhost:3000/user
Conclusion
Well Done! You have just built a simple web app using ExpressJS framework as a backend and Auth0 to authenticate and manage users. This tutorial was designed to help you understand APIs and how they work. Now you can use the knowledge gained here to build even better apps with scalable user management and authentication using Auth0.
Check out the repo for the app on GitHub. Also I’ve deployed a demo on heroku.
Kindly let me know if you have any questions or recommendations in the comment section.
For more information, check out this list of useful APIs for programmers. Have fun tearing them down.
Read up and Practice More!