Hugo and dynamic badges

Introduction

I have always liked the badges icons that we can see in a lot of websites, for website status, code status, and so on. They provide some usefull info in a quick glance. So another rainy day at home, I took the opportunity to look at how to add them. Crazy thing is, they are actually bringing dynamic infos to this static website ! Here are my findings.

Badge generation websites

There are actually several websites that are giving ways to generate those badges. Those websites are proposing some badges for well-known sites (Git-Hub, Jenkins, …). I have look on those 2 :

I have no idea which one is the best, but while reading the documentation of Shields.IO, I ve found the possibility to call any API returning a json payload, and that triggered my curiosity.

I thought a good idea would be to try showing the Crypto prices, as it changing a lot, it would be easier for me to test.

Crypto API

As Crypto prices seemed to be a good idea, I looked for a free API. I ve found out CoinGecko to provide a well documented API, also providing a Swagger documented API. Next step, query the API and output the expected json format for Shields.IO to generate the badge. To discover the list of coins, use the following :

https://api.coingecko.com/api/v3/coins/list

API Generator

While looking for an easy way to create an API endpoint available at all time, I have discovered Napkin.IO . That websites offers a free way to host up to 3 endpoints.

So I have created the following script and deployed it :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import fetch from 'node-fetch'

const etherPrice = async () => {
  const res = await fetch("https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=chf&include_market_cap=false&include_24hr_vol=false&include_24hr_change=false&include_last_updated_at=false&precision=2")
  const json = await res.json()
  const price = json.ethereum.chf+""
  const  [ints, decimals] = price.split(".")
  return ints.slice(0,-3) + "." + ints.slice(-3) + "," + decimals
}

export default async (req, res) => {
  const ether = await etherPrice()
  res.json({
    "schemaVersion": 1,
    "namedLogo": 'ethereum',
    "logoColor": 'yellow',
    "label": "EUR",
    "color": 'green',
    "message": `${ether}`
  })
}

To find out which logo to use, Shields.IO uses Simple Icons . The name of the icon name is available in that list. The interface allows to run the query, showing directly the payload received in json :

{
  "color": "green",
  "label": "EUR",
  "logoColor": "yellow",
  "message": "1.563,1",
  "namedLogo": "ethereum",
  "schemaVersion": 1
}

Hugo integration

The last step is to show the badge in one of the page generated in Hugo. I wanted to see the rates at all time, so I ve just added it in the footer. In the footer.html file at thew bottom, add the code below (in my case after the {{ partial "footer.html" . }}):

1
2
3
4
5
6
7
8
    ...
    <footer>
        <nav class="navbar fixed-bottom navbar-expand-lg bg-dark mt-auto py-3">
            <div><img class="ml-5" src="https://img.shields.io/endpoint?style=plastic&url=https%3A%2F%2F{NapkinAccount}.npkn.net%2F{FunctionName}"/>
            <div class="text-muted">Last Update : {{ dateFormat "2006-01-02 15:04 MST" now.Local }}</div>
        </nav>
    </footer>
    ...

And to add it to a markdown content, use the following structure :

![](https://img.shields.io/endpoint?style=plastic&url=https://{NapkinAccount}.npkn.net/{FunctionName})

Important note

Badges are cached, trying to refresh them too fast or too often will have no visible results. For Shields.IO, the badges are refreshed after min 6 minutes.

References