JavaScript and manipulating external data

JavaScript and manipulating external data

consuming and digesting other people's data

·

4 min read

Oftentimes, developers do not collecting the data for the websites they build; in this page, we will look at:

  • JSON (a nearly-universal data format)

  • fetch (a popular method to consume external data sources)

JSON (JavaScript object notation)

JSON (JavaScript Object Notation) allows for storing small sets of data in a relatively simple but robust structure:

The basic structure of a JSON object

The simplest JSON object looks like:

{ "property" : "value" }

In a browser console, let us take the basic JSON object above and assign it a variable called jsonObject:

> let jsonObject = { "property" : "value" };
<- undefined

It responds with "undefined" but let us enter the following again into the console to confirm that the object exists:

> jsonObject 
<- {property: "value"}

Notations for the notations

We could then use the dot notation object.property:

> jsonObject.property
<- "value"

Or, we could use the associative array notation object["property"]:

> jsonObject["property"]
<- "value"

The associative array notation becomes useful when the property names lengthen so much that we would need to use "kebab-notation", the stringing of multiple words with dashes!

let obj = { 
    "example-of-a-very-long-property-name" : "its value" 
}

We would then access that property like such:

> obj["example-of-a-very-long-property-name"]

Objects with more than one property

Naturally, an object could have multiple property-value pairs:

{ 
  "property1" : "value1", 
  "property2" : "value2", 
  "property3" : "value3", 
  ... 
}

Calling the above jsonObject, we would enter jsonObject.property2 or jsonObject["property2"] into a console to yield "value2":

> jsonObject["property2"]
<- "value2"

Objects inside of objects

The object could also have properties with values that themselves have sub-objects:

{ 
  "property1" : { 
    "property1A" : "value1A" 
  }, 
  "property2" : { 
    "property2A" : "value2A", 
    "property2B" : "value2B" 
  }, 
  "property3" : "value3" 
}

Calling the above jsonObject, we would enter jsonObject.property2.property2B or jsonObject["property2"]["property2B"] (a two-dimensional array) into a console to yield "value2B")

> jsonObject["property2"]["property2B"]
<- "value2B"

We can then infer here that this versatile structure could allow for quite complex objects with many properties and sub-properties to the desired degree!

Accessing JSON data with JavaScript

If we have a file named data.json on the same folder as the JavaScript file:

const request = new XMLHttpRequest()
request.open('GET', 'data.json', true)

request.onload = function() {
  if (this.status >= 200 && this.status < 400) {
    const data = JSON.parse(this.response)      
    // data here
    console.log(data)
  } else {
    // server error
  }
}

request.onerror = function() {
  // connection error
}

request.send()

Using fetch

This handy function called fetch() allows us to:

  • request access to an endpoint

  • receive, after the request finalizes,

    • a response (or error) from that endpoint

    • log, if a network error occurred, an error message

  • obtain the response data in JSON format

  • display the data, if available, on the front-end

GET requests

// fill in endpoint here
const url = ''; 

// GET or send error
// if GET successful, return JSON response
fetch(url)
.then(response => {
  if (response.ok) {
    return response.json();
  }
  throw new Error('Request failed!');
}, networkError => {
  console.log(networkError.message);
})
.then(jsonResponse => {
  return jsonResponse;
});

POST requests

// fill in endpoint here
const url = '';

// provide POSTing data as JSON object here
const dataBody = { whatever: "here" };

// set up the data payload
const data = { method: 'POST', body: dataBody };

// POST or die
// if POST successful, return the confirmation as JSON
fetch(url, data)
.then(response => {
  if (response.ok) {
    return response.json();
  }
    throw new Error('Request failed!');
}, networkError => {
    console.log(networkError.message);
})
.then(jsonResponse => {
  return jsonResponse;
});

Async and await (ES8)?

ES8 allows us to use async and await keywords to access external data:

GET requests

Note the async before the function declaration and the two uses of await, one for the fetch response and then another one for the JSON response:

// fill in endpoint here
const url = '';

const getData = async () => {
  try {
    const response = await fetch(url);
    if (response.ok) {
     const jsonResponse = await response.json();
    }
    throw new Error('Request failed!');
  } catch (error) {
    console.log(error);
  }
}

POST requests

The POST request follows the same pattern as the GET but with an additional argument inside the fetch for the data that we will POST:

// fill in endpoint here
const url = ''; 
const dataBody = { whatever: "here" };

const getData = async () => {
  try {
    const response = await fetch(url, {
      method: 'POST',
      body: dataBody
    });
    if (response.ok) {
      const jsonResponse = await response.json();
      return jsonResponse; 
    }
    throw new Error('Request failed!');
  } catch (error) {
    console.log(error);
  }
}

The async keyword creates a function that returns a Promise to await for responses from the API, before we proceed along the code blocks ... then, we can simply handle any errors and place any valid responses into getData!