Desarrollo y Mantenimiento de Sistemas Informáticos

4º. 1er cuatrimestre. Itinerario de Sistemas de la Información. Grado en Ingeniería Informática. ULL


Organization DMSI org   Github Classroom DMSI class   Campus Virtual DMSI campus   Profesor Casiano   Chat Chat

The JAM Stack

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

Multiple Ways of API Integration in your JAMStack

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.

Option One - Direct Access to a Remote API

<!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>

Option Two - An API Proxy

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:

  1. First, HERE’s weather API supports returning astronomy data. For my demo I want to know about the moon, so you can see me filtering that out in the map call. This will result in less data going to be my client-side code.
  2. Also note that the API has slightly different casing going on. So for 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?