3º. 2º cuatrimestre. Itinerario de Tecnologías de la Información. Grado en Ingeniería Informática. Curso 2019/2020
You may have already seen or worked on a Jamstack site! They might be built using by hand, or with Jekyll, Hugo, Nuxt, Next, Gatsby, or another static site generator…
When adding interactivity to a JAMStack site, typically you think of APIs, remote services that can be used to get dynamic data which is then rendered on your site with JavaScript. But there’s multiple ways of using those APIs, and JavaScript, that may not be apparent to you at first.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://vuejs.org/js/vue.min.js"></script>
<title>SWAPI Example</title>
</head>
<body>
<div id="app">
<h1>Star Wars Films</h1>
<ul>
<li v-for="film in films">{{ film.title }}</li>
</ul>
</div>
<script>
const app = new Vue({
el:'#app',
data: {
films:[]
},
created() {
fetch('https://swapi.co/api/films')
.then(res => res.json())
.then(res => {
this.films = res.results;
let titles = this.films.map(x => x.title);
console.log(titles);
});
}
});
</script>
</body>
</html>
The second option is pretty similar to the first, with the main difference being that your code hits an API running on your server. The server could be just that, an app server running somewhere in house, but typically will be a serverless platform instead. Basically, instead of your code making an HTTP request to some remote domain, it requests your code which then itself requests data from the remote domain.
Consider this example using the Weather API from https://developer.here.com/documentation/examples/rest/auto_weather/weather-forecast-7days-astronomy. Their API requires two specific authentication values, an app_id
and app_code
. If I put that in my client-side code, anyone could use it, which wouldn’t be desirable. I’m going to use a serverless proxy set up with Netlify Functions to proxy requests to HERE’s API from my client side code.
const fetch = require("node-fetch");
exports.handler = async function(event, context) {
try {
let app_id = process.env.HERE_APP_ID;
let app_code = process.env.HERE_APP_CODE;
const response = await fetch(`https://weather.api.here.com/weather/1.0/report.json?app_id=${app_id}&app_code=${app_code}&product=forecast_astronomy&name=Lafayette,LA`, {
headers: { Accept: "application/json" }
});
if (!response.ok) {
// NOT res.status >= 200 && res.status < 300
return { statusCode: response.status, body: response.statusText };
}
const data = await response.json();
let results = data.astronomy.astronomy.map(r => {
return {
moonRise:r.moonrise,
moonSet:r.moonset,
moonPhase:r.moonPhase,
moonPhaseDesc:r.moonPhaseDesc,
time:r.utcTime
}
});
return {
statusCode: 200,
body: JSON.stringify({ data:results })
};
} catch (err) {
console.log(err);
return {
statusCode: 500,
body: JSON.stringify({ msg: err.message })
};
}
};
In general this is just some trivial Node code, but I want to point out some specific tweaks I did here:
map
call. This will result in less data going to be my client-side code.moonrise
it’s all lowercase, but then they use moonPhase
. There may be a good reason for that, but to me it wasn’t what I expected so I took the opportunity to reformat the data a bit as well.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://vuejs.org/js/vue.min.js"></script>
<title>Moon Data</title>
</head>
<body>
<div id="app">
<h1>Moon Data for Lafayette, LA</h1>
<ul>
<li v-for="result in results">
On , the moon will rise at and set at . It is in .
</li>
</ul>
</div>
<script>
Vue.filter('formatDate', function(d) {
if(!window.Intl) return d;
return new Intl.DateTimeFormat('en-US').format(new Date(d));
});
const app = new Vue({
el:'#app',
data: {
results:[]
},
created() {
fetch('/.netlify/functions/get-moon')
.then(res => res.json())
.then(res => {
this.results = res.data;
});
}
});
</script>
</body>
</html>
So, this one is a bit more work, but depending on your app platform, it could be easy. As I said, I used Netlify Functions, and outside of a configuration issue I had, it was trivial. What does this give us?