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
!