Server-Side Scripting/Internet Data/Node.js (Express)

routes/lesson8.js

edit
// This program reads JSON data from Wikidata with countries
// and Celsius temperatures. It displays the data in Celsius
// and Fahrenheit sorted in decending order by temperature.
//
// References:
//  https://www.mathsisfun.com/temperature-conversion.html
//  https://en.wikibooks.org/wiki/JavaScript
//  https://www.wikidata.org/wiki/Wikidata:SPARQL_query_service
//  https://hackersandslackers.com/making-api-requests-with-nodejs/
//  https://zellwk.com/blog/async-await-express/

const express = require('express')
const fetch = require('node-fetch');
const fs = require("fs");
const handlebars = require('handlebars');
const router = express.Router();

const URL = "https://query.wikidata.org/sparql";
const QUERY = `
SELECT DISTINCT ?Country ?MaximumTemperature WHERE {
  ?countryItem wdt:P31 wd:Q6256;
    p:P6591 ?maximumTemperatureRecord.
  ?maximumTemperatureRecord psv:P6591 ?maximumTemperatureValue.
  ?maximumTemperatureValue wikibase:quantityAmount ?maximumTemperatureQuantity;
    wikibase:quantityUnit ?temperatureUnit.
  {
    ?countryItem rdfs:label ?Country.
    FILTER((LANG(?Country)) = "en")
  }
  {
    ?temperatureUnit wdt:P5061 ?unitSymbol.
    FILTER((LANG(?unitSymbol)) = "en")
    FILTER(CONTAINS(?unitSymbol, "C"))
  }
  BIND(CONCAT(STR(?maximumTemperatureQuantity), " ", ?unitSymbol) AS ?MaximumTemperature)
}
ORDER BY (?Country)
`;

router.get("/", async function (request, response) {
    result = await getData();

    let source = fs.readFileSync("./templates/lesson8.html");
    let template = handlebars.compile(source.toString());
    let data = {
        table: result
    }
    result = template(data);
    response.send(result);
});

async function getData() {
    try {
        let data = await getRawData(URL, QUERY);
        let records = getRecords(data);
        records.sort(function(a, b) {return b.celsius - a.celsius});
        let result = formatTable(records);
        return result;
    }
    catch(error) {
        return error;
    }
}

async function getRawData(url, query) {
    url += "?query=" + encodeURI(query);
    url += "&format=json";

    let response = await fetch(url);
    if (!response.status == 200) {
        throw(response.statusText)
    }

    return response.json()
}

function getRecords(data) {
    let records = [];
    for (let i = 0; i < data.results.bindings.length; i++) {
        let record = getRecord(data.results.bindings[i]);
        records.push(record);
    }
    return records;
}

function getRecord(object) {
    let country = object.Country.value;
    let celsius = object.MaximumTemperature.value;
    let index = celsius.indexOf(" °C");
    if (index < 0) {
        throw "Invalid data format";
    }

    celsius = Number(celsius.substring(0, index));
    let fahrenheit = celsius * 9 / 5 + 32;

    let record = {};
    record.country = country;
    record.celsius = celsius;
    record.fahrenheit = fahrenheit;
    return record;
}

function formatTable(records) {
    let result = "<table><tr><th>Country</th>"
    result += "<th>Celsius</th>";
    result += "<th>Fahrenheit</th></tr>";

    for (index = 0; index < records.length; index++) {
        let record = records[index];
        result += "<tr><td>" + record.country + "</td>";
        result += "<td>" + record.celsius.toFixed(1) + "° C</td>";
        result += "<td>" + record.fahrenheit.toFixed(1) + "° F</td></tr>";        
    }

    result += "</table>";
    return result;
}

module.exports = router;

templates/lesson8.html

edit
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Lesson 8</title>
    <link rel="stylesheet" href="styles.css">
    <style>
        p {
            min-height: 1em;
        }
    </style>
</head>

<body>
    <h1>Temperature Conversion</h1>
    <h2>Wikidata</h2>
    {{{table}}}
</body>

</html>

Try It

edit

See Server-Side Scripting/Routes and Templates/Node.js (Express) to create a test environment.