Web Platform Javascript

Data storage

Here, we'll introduce two simple ways of storing data. The first stores data in the browser itself, using "local storage". The second uses one of several free services that allow you to save a chunk of JSON to a server.

If you want data to be accessible between different devices/users or survive for a longer time, you'll want to the latter option - saving it to the server.

In these examples we'll only consider basic needs. If you want to save large amounts of data and perform queries, look at a service like Firebase.

Local storage

Local storage is available in all modern browsers and has an extremely simple API. With local storage, you save or retrieve data by a key.

For example:

// Save examples
localStorage.setItem('name', 'Thom');
localStorage.setItem('name', document.getElementById('name').value);

// Get
const name = localStorage.getItem('name');

// Remove
localStorage.removeItem('name');

With local storage, everything you set should be a string - or at least automatically convertible to a string. Everything you get back via getItem will be a string.

For example

localStorage.setItem('age', 55); // Save an integer value
const age = localStorage.getItem('age'); 
// 'age' will be of type string: "55" rather than just 55

localStorage.setItem('acceptedTerms', true); // Save a boolean
const hasAccepted = localStorage.getItem('acceptedTerms');
// 'hasAccepted' will be the string "true" not the real boolean of true

Depending on what you're doing with the return values, you may need to convert them to their proper data type. For numbers you could use parseInt or parseFloat:

const age = parseInt(localStorage.getItem('age')) // 'age' will be of type number

For booleans, test the string value

const hasAccepted = localStorage.getItem('acceptedTerms') === 'true';
// hasAccepted will be boolean

null will be returned if the key doesn't exist:

if (localStorage.getItem('age') == null) {
  // No, key 'age' has not been saved yet
}

Objects

If you want to get and save entire objects or arrays, you can convert to and from a JSON string.

// Our complex data
const fruits = [
  { name: 'Banana', colour: 'yellow' },
  { name: 'Strawberry', colour: 'red' },
  { name: 'Potato', colour: 'white' }
];

// Save by passing through JSON.stringify
localStorage.setItem('fruit', JSON.stringify(fruits));

...

// Retrieve and convert to object with JSON.parse
const fruits = JSON.parse(localStorage.getItem('fruit'));
if (fruits == null) {
  // Key has not been set
}

Read more

Server storage

We're going to use the fetch API to save and fetch data from JSONbin, a free service. You need to sign up and generate an API Key.

In JSONbin's model, you have to have a "bin" to save data into. So first you have to create a bin, either with a POST request, or via their UI.

The Fetch API is based on the concept of "promises". The code looks a little different since it's made up of "chained" methods:

fetch( ... ).then( ... ).catch( ... ).then( ... )

Promises simplify writing asynchronous code - things which run but you won't know the result of until later. Since we're communicating with a third party server it takes time for things to happen and of course things can go wrong in all sorts of ways. Promises are a great fit. In essence, a promise allows you to say (in code) "do this, and then when that's done, do this other thing, and if a problem happens do this, and after that do this" and so on.

Here's an example of creating a new bin:

const fruits = [
  { name: "Banana", colour: "yellow" },
  { name: "Strawberry", colour: "red" },
  { name: "Potato", colour: "white" }
];
const headers = {
  'X-Master-Key': 'YOURKEY',
  'X-Bin-Private': true,
  'Content-Type': 'application/json'
 };

fetch('https://api.jsonbin.io/v3//b', {
  method: 'POST',
  body: JSON.stringify(fruits), 
  headers: headers
}).then(res => res.json()) // Convert to JSON
  .catch(error => console.error('Error:', error))
  .then(response => {
    console.log('Success:', response);

    // We get back the id of the bin
    bin = response.metadata.id
});
}

If you have a bin id, you can update the data. The server keeps the old copy of your data in version.

const bin = 'YOUR BIN ID';
fetch('https://api.jsonbin.io/v3/b/' + bin, {
  method: 'PUT',
  body: JSON.stringify(fruits), 
  headers: headers)
}).then(res => res.json())
  .catch(error => console.error('Error:', error))
  .then(response => {
    // Success!
  });

To get the data, you'll again need the bin id. Note that we access the newest version of the bin by appending /latest to the constructed URL.

const bin = 'YOUR BIN ID';
fetch('https://api.jsonbin.io/v3/b/' + bin + "/latest", { headers: headers })
.then(res => res.json())
.then(res => {
  for (fruit of res.record) // res.record holds the data
    fruits.push(fruit);

  // do something with the data...

See a complete demo

Read more