Introduction to Firebase's Storage

aurelkurtula

aurel kurtula

Posted on December 11, 2017

Introduction to Firebase's Storage

In the introduction to firebase's real-time database tutorial I explained how we can use firebase to store, retrieve and edit data in a non-sql real-time database.

Storage is another service that firebase provides. Using this service we are able to upload and use files to google's cloud. Basically, we are able to upload our webpage assets and use them as if they were hosted in our own server.

Setting up our files

The last tutorial covered how to set up a fire base project. If you haven't read that, you definitely should. Then, you can simply continue with this tutorial.

Wellcome back :)

So, we have two files, the HTML an JavaScript file. The HTML is going to have a file input button, that's how we will upload files.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Firebase Storage</title>
        <script type="text/javascript" src="https://www.gstatic.com/firebasejs/4.8.0/firebase.js"></script>
    </head>
    <body>
        <div id="uploading">
                <progress value="0" max="100" id="progressBar">0%</progress>
                <label for="submit">Click to upload</label>
                <input type="file" value="upload" id="submitButton" />  
        </div>  
        <script type="text/javascript" src="script.js"></script>
    </body>
    </html>
Enter fullscreen mode Exit fullscreen mode

As covered in the last tutorial, we have the filebase library at the top, our script file at the bottom. An input field to upload the file, where as the lable and progress are simply for decore!

I'll leave the css up to you but to illustrate what we are doing, this is what I have (with the help of css)

img

We'll need to use the initial Firebase configuration code, as we did in the last tutorial, everything apart from the sections concerning the database. Add the following to the script.js:

    var config = {
      apiKey: "*******************",
      authDomain: "******.firebaseapp.com",
      databaseURL: "https://******.firebaseio.com",
      projectId: "******",
      storageBucket: "******.appspot.com",
      messagingSenderId: "***************"
    };
    firebase.initializeApp(config);
Enter fullscreen mode Exit fullscreen mode

Setting up storage restrictions

Just as we've done with the database, in order to play around with storage we need to remove the restrictions so that we can read and write without needing authentication. It's clearly a bad idea to do this in production but this is just to give us the freedom to learn this service in isolation.

All you need to do is navigate to Storage then rules and then edit read and write privileges to true

img

Working with storage()

If you navigate to Storage, then files you'll see the message, "there are no files here yet". Our aim in this tutorial is to add files in there from our web app/site.

Let's do that.

In script.js let's initialise the Storage() service.

const storage = firebase.storage()
Enter fullscreen mode Exit fullscreen mode

There's a two step process to uploading a file to the storage. Firstly we need to specify where we want the file to go and what name it should have.

let locationRef = storage.ref('cats/cat1.jpg')
Enter fullscreen mode Exit fullscreen mode

Above we are saying call the file cat1.jpg and add it into a folder cold cats.

So far that's just a reference, it does nothing, it simply waits for the file to be put into it. The following line actually pushes the local file to the firebase server.

locationRef.put([the file])
Enter fullscreen mode Exit fullscreen mode

Uploading files to firebase storage

As you saw, there are only three lines of code to get an asset stored in the firebase storage. Now let's use those in combination with vanilla JavaScript to make actual uploads.

In our HTML we had this code

<label for="submit">Click to upload</label>
<input type="file" value="upload" id="submitButton" /> 
Enter fullscreen mode Exit fullscreen mode

A user clicks on the input/label, then is required to select an asset and finally we want to upload that asset to firebase

const storage = firebase.storage()
const submitButton = document.getElementById('submitButton');
submitButton.addEventListener('change', (e)=>{
  let file = e.target.files[0];
  let locationRef = storage.ref('cats/' + file.name)
  locationRef.put(file)
})
Enter fullscreen mode Exit fullscreen mode

As you can see, the exact same lines. This time the name of the file will be the same name of the local file, and the file being pushed to the server is the file itself.

If you go back to the firebase console, to Storage, you'll see your cats folder and inside it, your cat photos!

Getting feedback from the process

As usuall when considering user experience we need to be able to provide information through out the process. For example it be cool to know:

  • How long the upload is taking?
  • did it actually upload successfully?
  • What is the new location address?

Similar to the database() service, storage() also has an on() method which observes state_changed observer, within which we are able to observe the uploading process, catch any errors, and be aware when the upload is complete.

submitButton.addEventListener('change', (e)=>{
  let file = e.target.files[0];
  let locationRef = storage.ref('cats/' + file.name)
  let task = locationRef.put(file)
  task.on('state_changed',
      function progress(snapshot){
        // whilst uploading
      },
      function error(error){
        //error handling
      },
      function complete(){
        // on completion
      }
  )
})
Enter fullscreen mode Exit fullscreen mode

Note how we attached locationRef.put(file) to a variable, now we are able to observe it's state throughout the process:

task.on('state_changed', 
  function progress(snapshot){ //progress
    let per = (snapshot.bytesTransferred / snapshot.totalBytes) *100;
    uploader.value = per;
  },
  function error(error){ },
  function complete(){
    console.log('Done') 
  }
)
Enter fullscreen mode Exit fullscreen mode

The first function watches the process, and as you can see, it gives us the total number of bytes of the original file, and the number of bytes that have been uploaded. We are using those numbers to get a percentage and we are adding that to the progress. Incase it's confusing uploader refers to the progress element:

<progress value="0" max="100" id="progressBar">0%</progress>    
let uploader = document.getElementById('progressBar')
Enter fullscreen mode Exit fullscreen mode

Reading files from storage

In order to get a file out of storage, you need to know the folder it's in and its file name. With that the full url can be found.

let storageRef = storage.ref('cats')
let image = storageRef.child('cat1.png');
Enter fullscreen mode Exit fullscreen mode

The above can be writen in one line as we'll see later on:

let storageRef = storage.ref('cats/cat.png');
Enter fullscreen mode Exit fullscreen mode

To get the actual url and display it on the page:

image.getMetadata().then(function(metadata) {
  document.getElementById('img').src = metadata.downloadURLs[0]
}).catch(function(error) { /*error handling*/ });    
Enter fullscreen mode Exit fullscreen mode

Assuming we had an image tag with the id of img, the cat from storage would be sat on the browser :)

Deleting files

Deleting is just as simple as everything else, follows the same pattern: point to the file, then run delete() on it

let storageRef = storage.ref('cats/cat.png');
storageRef.delete().then(function() {
  // removed
}).catch(function(error) {
  // not removed :(
});
Enter fullscreen mode Exit fullscreen mode

Combining storage with the database

I should end the tutorial here but just because the main reason I can think of that google gave storage with firebase is so that it can be used with the database, I am going to combine the two right now!

Let's revisit the event listener from above:

submitButton.addEventListener('change', (e)=>{
  let file = e.target.files[0];
  let locationRef = storage.ref('cats/' + file.name)
  let task = locationRef.put(file)
  task.on('state_changed',
      ...
      function complete(){
        // on completion
      }
  )
})
Enter fullscreen mode Exit fullscreen mode

When the uploading is complete we want to store the full url to the database.

You can easily do this yourself by following the last tutorial

const database = firebase.database()
const ref = database.ref('cats');
submitButton.addEventListener('change', (e)=>{
  ...
  task.on('state_changed',
      ...
      function complete(){
        storageRef.getMetadata().then(metadata=>{
         ref.push({
          url: metadata.downloadURLs[0]
        })
        })
      }
  )
})
Enter fullscreen mode Exit fullscreen mode

Exactly the same as in the last tutorial, in lines 1-2 we define the database service and where the content should go. Inside complete function (which doesn't have to have a name, as you know) we push to the database. Now if you check the database, you'll see a cats node and a child node with the cat url. Note that metadata gives more information, such as the time when the file was uploaded and so you can get more information to store in the database.

Conclusion

This was fun. Stay tuned for few more tutorials on firebase. I have authentication to cover, and production mode (covering how we can protect the configuration settings), then anything else that I might think of conserning firebase services.

💖 💪 🙅 🚩
aurelkurtula
aurel kurtula

Posted on December 11, 2017

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related