Blog

I write on blua.blue, dev.to and others

How to Build an Express App in Node That Reads From a Headless CMS

Introduction

I assume that you will read tutorials like I do: having your IDE ready to follow along. I also assume that you are familiar with basic JavaScript and have node & npm installed. My targeted audience is the "advanced beginner", so someone who has basic understanding of the environment and languages but needs a little guidance on how to start building great applications, or the advanced creator who collects ideas and dabbles into new worlds. You can also download the complete project and use this tutorial as explanation.

Complete files: Download ZIP View on GITHub

blua.blue

The headless neoan3 based CMS blua.blue is open source and can be hosted wherever you want. For this simple tutorial, we are going to sign up here: blua.blue registration

After confirming our email, we are ready to use the API to our liking. It might make sense to write your first article if you feel like it (as a matter of fact, this very toturial has been created in blua.blue).

We are using node as once we gather are solid understanding of the capabilities of a headless CMS, we will see the SEO advantage of rendering content server side (but that is a topic for another post).

1. Installing prerequisites

Let's create a project folder. You can name this folder however you want, but I will simply refer to it as "app-folder" here. Let us start by installing the we will need via npm

npm install express pug axios --save

While express will be our server we will use pug (former jade) as a template engine and axios to handle our requests to blua.blue

By default, express expects templates to be in the folder views, so we might as well create this folder now. To present you with an overview, this will be the file structure at the end:

views/

-- list.pug

blua-api.js

server.js

To give express a basic spin, let's test if everything runs: Create a file list.pug in /views and enter some basic markup.

html
    head
        title My articles   
    body
        h1 Test

Now we create the file (if you haven't already) server.js and start defining your express server:

const express = require('express');
const app = express();

// Routing is crucial. If you are not familiar with route definitions, please look into express documentation 

app.get('/', function (req, res) {
       res.render('list', function(err,html){
            res.send(html);
        })
});

// And let us serve on port 3000 
app.listen(3000, function () {
    console.log('Example app listening on port 3000!');
});

Running node serve.js should give us a running application @ http://localhost:3000

2. Api wrapper

One could argue that it is overkill for our purposes, but I want to create a setup that allows you to go beyond this tutorial with the codebase we create. Let us therefore create the file blua-api.js now:

const axios = require('axios');

// Change this line if you are hosting blua.blue yourself
let baseUrl = 'https://blua.blue/api.v1/';

const api = {
    config: {
        baseURL: baseUrl,
        timeout: 2000,
        headers:{}
    },
    token: false,
    connected:false,
    init: async (user, password) => {
        if(!this.connected){
            let instance = axios.create(api.config);
            await instance.post('login',{username:user,password:password}).then(res=>{
                api.token = res.data.token;
                api.connected = true;
                api.config.headers.Authorization = `Bearer ${res.data.token}`;
                instance = axios.create(api.config);
            }).catch(err=>{
                console.log(err);
                process.end()
            });
            return instance;
        }
    }
};

module.exports = api;

As you can see we are prepared to make authorized calls with a JWT token with one simple step. The function init returns an axios instance. If you are not familiar with axios, or would rather use javaScript's fetch, feel free to implement another solution. Here we want to make sure that the very first call authenticates us and all subsequent calls are authenticated. The usage will be:

const bluaBlue = require('./blua-api.js');

bluaBlue.init('your-username','your-password').then(api=>{
    // make any call documented in https://blua.blue/api-documentation
    api.get('article?slug=my-article').then(...);

});

Note: While not covered in this tutorial, your JWT will expire once in a while. You will receive "unauthorized" 401 responses in such cases that you can catch. You may simply run init again but set the wrappers property connected to false so authentication runs again.

3. Collecting & Rendering a list of your articles

I don't want to get into design in this tutorial, so we'll use bootstrap for a basic expandable list since I think most people have at least a minimum experience with it. 

More or less taken exactly from bootstrap's documentation, let's get back and enhance our template (views/list.pug)

html
    head
        title My articles
        // let's use the bootstrap files via CDN
        link(rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css")
        script(src="https://code.jquery.com/jquery-3.3.1.slim.min.js")
        script(src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js")
        script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js")
    body
        .container
            h1 My articles
            .accordion#article-list
                // We don't have any articles yet, but we will want to iterate over them.
                each article in articles
                    .card
                        .card-header
                            h2.mb-0
                                button.btn.btn-link(type="button" data-toggle="collapse" data-target="#"+article.slug) #{article.name}
                        .collapse(id=article.slug data-parent="#article-list")
                            .card-body
                                p #{article.teaser}
                                a.btn.btn-success(href="https://blua.blue/article/"+article.slug target="_blank") read

So what do we want to achieve? Our app is supposed to fetch all articles of a particular author (you?) and list them. So we will redesign our server.js to make a call to blua.blue when a client requests the home page ( get('/') ). As mentioned before, the api wrapper sends authenticated calls after initiation. The easiest approach is to wrap our server logic in this wrapper.

const express = require('express');
const app = express();
app.set('view engine', 'pug');
const bluaBlue = require('./blua-api.js');


// you will want to set your credentials right
bluaBlue.init('your-username','your-password').then(blua=>{
    app.get('/', function (req, res) {
        // set the author accordingly. If you have not written any articles yet, use "neoan" to test
        blua.get('articleList?author=your-username').then(d=>{
            // be sure to include the data here
            res.render('list', {articles:d.data}, function(err,html){
                res.send(html);
            })
        });
    });

    app.listen(3000, function () {
        console.log('Example app listening on port 3000!');
    });
});

That's it!

If you run in any problems when running node server.js , you might want to run your application in debug mode. For Windows this means running set DEBUG=express:* node server.js .

Now you are on your own. Can you create dynamic routes for your articles rather than directing the visitors to blua.blue? Can you look into the objects and find additional content you want to use? Are you bold enough to try to update one of your articles?

 

image

Stop learning what you think is relevant

Still learning react, laravel & co? You better plan ahead!

image

How to use JWT in the neoan3 PHP framework

Many things have changed since I last addressed implementing JWT & stateless authentication & authorization.

image

Rapidly build your own stateless REST-API with neoan3

One of the most common tasks for a web-developer is interacting with an authenticated backend. While a plethora of possibilities are available, the way neoan3 handles things is not only convenient, but also fast and reliable.

image

Generating Phaser Game assets: Planet spritesheet generator

Ever needed to automate a process and all of a sudden you built a tool?

image

Do you even write?

Using the blua.blue webhook in order to track your writing.

Install PHP 8 on Ubuntu

PHP8 has finally been released and it is FAAAAST! Time to update.

image

6 Technologies to look at in 2021

2020 wasn't the best year humans can look back to. but what does 2021 bring for coders?

image

CSS Grid or CSS framework - are they really exclusive?

Grid-based or framework - there are many articles about this choice. But why is that even a thing?

image

Scaffolding REST APIs with JWT authentication

Ever had the need for your own backend while developing your web-app?

image

What is composer?

Composer has become PHP's package & dependency manager. Why you should use it.

image

MySQL: ERROR1364 fix

The painful realization of why people use containers.

image

Cyber wars: Defending your server

Maintaining your own server can be a thrill. High security standards can protect you from data leakage, injection attacks and DDoS attempts. But what about adaptive brute force?

Git: globally change GitHub-remotes from git@ to https

Does your IDE or composer set remote repositories to ssh rather than https? Or are repositories you are using set up that way? You are not alone. Let's fix it once and for all!

VueJS & neoan3: a love story.

Setting up neoan3 to play nice with Vue isn't hard. Here is how the two frameworks are combined to support fast, dynamic and rapid development.

image

MySQL in PHP - how to deal with databases

How I handle MYSQL database transactions in PHP

Install PHP 7.4 on Ubuntu

Finally PHP 7.4 is out! You have read about the new features, you have followed externals, you have gathered ideas on how new capabilities will save time. Let's get it running.

How to install global npm packages without sudo on Ubuntu

Running npm on a server can be painful. Privileges are there for a reason, and so is sudo. Running npm with sudo is not the solution.

image

Static content pages - still the fastest web-experience

Tutorial: How to utilize blua.blue to generate static content for your website.

image

Cross publishing to dev.to

How to publish your content to dev.to from blua.blue - hopefully

The Uselessness of Pre-Assessment

After almost two decades in the industry, new jobs will still ask you for "assessment tests". A little rant...

image

SEO strategies for blua.blue

How to get your content listed where you want it to.

image

How to Build an Express App in Node That Reads From a Headless CMS

A headless CMS lets you design your own front-end, sometimes your own back-end. Let's set up a small application to get us started. Beginner friendly. Approx. 20 min. to reproduce / follow along

Transformer - falling in love with PHP's magic methods all over again

PHP's magic functions have been around for a long time. But there were always good reasons to avoid them. Transformer is a practical and reliable way to make use of the most common operations we program: CRUD operations.

image

Help us document neoan3

Over 4000 brave developers are exploring the framework on their own.

image

When politics kill innovation

How misunderstood diversity killed the PHP Central Europe Conference for good.

image

blua.blue PHP SDK

Create your own blog.

image

dev.to plugin for headless CMS blua.blue (part 2)

A solution to supplying plugins to blua.blue