La diffusion des articles de blog sur différentes plateformes/sites est un besoin qui revient souvent lorsque l'on utilise un CMS pour la rédaction de ces contenues.
Nous allons ici voir comment grâce à l'API REST de Bludit (cms utilisé pour mon blog) diffuser la publication des articles différents sites.
Exemple sur mon site de développeur freelance yanncarlen.com :
Les technologies abordées ici sont :
- Bludit, cms flat-file que nous utilisons très souvent pour sa simplicité et son efficacité
- Hapi, framework Node.js
- jQuery que tout le monde connait
Vous retrouverez ici les sources du projet : https://github.com/Zenicheck/blog/tree/master/bludit-api-hapi
Mise en place d'Hapi :
$ npm init
$ npm i @hapi/hapi @hapi/boom axios
On a donc un package.json suivant (à adapter bien sur) :
{
"name": "bludit-api-hapi",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node --experimental-modules --experimental-json-modules app.mjs",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Zenicheck/blog.git"
},
"author": "Yann Carlen - Zenicheck",
"license": "MIT",
"bugs": {
"url": "https://github.com/Zenicheck/blog/issues"
},
"homepage": "https://github.com/Zenicheck/blog#readme",
"dependencies": {
"@hapi/boom": "^9.1.0",
"@hapi/hapi": "^19.1.1",
"axios": "^0.19.2"
}
}
Utilisation de l'API de Bludit :
Pour utiliser l'api rest de Bludit le plus simple est de se référer à la documentation du cms : https://docs.bludit.com/en/api/introduction
Une fois le plugin activé et votre clef d'api récupérée vous pouvez tester le bon fonctionnement de l'api en testant son appel avec curl (attention il faut spécifier un user agent sinon vous récupérez un 403 ) :
$ curl -X GET \
-A "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0" \
-G "https://YOUR-URL.com/api/pages" \
-d "token=YOUR-KEY" -d "published=true" \
-d "static=true"
En remplacent évidemment YOUR-URL par l'url de votre blog et YOUR-KEY par votre clef d'api.
Développement de l'API avec Hapi et axios :
Les particularités ici sont l'injection de la configuration par les variables d’environnement (exemple plus bas), l'utilisation du CORS afin de pouvoir faire des appels à l'api depuis un autre domaine et enfin, le plus important la mise en cache du résultat de la requête afin d'éviter de faire un appel à l'api de Bludit à chaque appel dans le but de gagner en performances et surtout parce que la publication d'articles change de manière journalière et non pas de manière horaire.
/* app.mjs */
import Hapi from '@hapi/hapi'
import Boom from '@hapi/boom'
import axios from 'axios'
const init = async () => {
const server = Hapi.server({
port: process.env.PORT || 3000,
host: '0.0.0.0',
routes: {
cors: true
}
})
const { HOST, TOKEN } = process.env
const params = {
token: TOKEN,
static: false,
published: true
}
server.route({
method: 'GET',
path: '/',
handler: async (request, h) => axios.get(HOST + '/pages', { params })
.then(e => e.data.data.map(e => ({
permalink: e.permalink,
title: e.title,
description: e.description,
category: e.category,
coverImage: e.coverImage,
tags: e.tags,
date: e.date
})))
.catch(() => Boom.badRequest('invalid query')),
options: {
cache: {
expiresIn: 3600 * 1000,
privacy: 'private'
}
}
})
server.events.on('response', request => {
console.log(request.info.remoteAddress +
': ' +
request.method.toUpperCase() +
' ' +
request.path +
' --> ' +
request.response.statusCode)
})
await server.start()
console.log('Server running on %s', server.info.uri)
}
process.on('unhandledRejection', (err) => {
console.log(err)
process.exit(1)
})
init()
L'objet retourné est donc un tableau d'articles formaté aux besoins des autres plateformes qui vont consommer l'information.
Lancement de l'application :
$ PORT=7900 HOST=https://YOUR-HOST.com/api TOKEN=YOUR-KEY npm start
Puis :
$ curl -X GET http://localhost:7900
Il va maintenant être temps de s'occuper de la partie front afin de pouvoir récupérer les informations de cette api est de les afficher.
Récupération des derniers articles avec jQuery :
Prenons l'optique d'un site utilisant Bootstrap avec une section de page suivante :
<!-- ... -->
<div class="row">
<div class="col-md-12">
<!-- Section Title Start -->
<div class="section-title">
<h2>Derniers posts du blog</h2>
</div>
<div class="row" id="blog-post">
</div>
</div>
</div>
<!-- .... -->
L'idée est donc d'injecter les articles sur la balise ayant pour id : blog-post
Ce qui donne le script suivant en incluant évidemment jQuery en amont (ici en version 2.2) et en remplacent YOUR-API-URL par l'url de votre api :
$(document).ready(function () {
const blog = $('#blog');
const blogPost = $('#blog-post');
blog.length && fetchLatest(blogPost);
function fetchLatest(blogPost) {
$.get('https://YOUR-API-URL/').done(function (data) {
if (data.length > 3) data = data.splice(0, 3);
data.forEach(function (e) {
blogPost.append(`
<div class="col-md-4 mb-sm-30">
<div class="blog-item" >
<div class="blog-item-img">
<a href="${e.permalink}" target="_blank">
<img src="${e.coverImage}" alt="${e.title}" class="img-responsive">
</a>
</div>
<div class="blog-item-content">
<h2><a href="${e.permalink}" target="_blank">${e.title}</a></h2>
<div class="metadata">
<i class="fa fa-calendar"></i> ${e.date}
<span class="divider">|</span>
<i class="fa fa-user"></i> Yann Carlen
</div>
<p>${e.tags.split(',').map(function (f) { return `<span class="label label-primary" style="font-size: 13px; line-height: 2;">${f}</span>` }).join(' ')}</p>
<a href="${e.permalink}" class="read-more-btn" target="_blank"><i class="fa fa-angle-double-right"></i> Lire l'article</a>
</div>
</div>
</div>
</div>`);
});
});
}
});
On récupère ici la liste des articles en ne conservant ici que les trois premiers puis ajoutons les tiles des articles à la div "blog-post".
Ce qui donne le visuel suivant :
Si vous cherchez un développeur Node.js afin de réaliser votre site ou de vous accompagner sur une autre problématique n'hésitez pas à me contacter !
Vous retrouverez ici les sources du projet : https://github.com/Zenicheck/blog/tree/master/bludit-api-hapi