DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป

DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป is a community of 966,904 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Akira Kashihara
Akira Kashihara

Posted on

How to upload files to Google Cloud Storage using Javascript on only the browser

This article shows how to upload files to Google Cloud Storage using Javascript on only the browser (without Node.js).

Implementation

This source code was made based on GCP(Google Cloud Platform) Official reference. This article uses JSON API GCP provides and OAuth2.0.

Auth (OAuth2.0)

The goal in this section is to get an access token to access Cloud Storage. We get it through Google OAuth2.0. "OAuth 2.0 for Client-side Web Applications" shows us the necessary source code for authorization. This is a reference to make the following source code.

Get Necessary Information

You need to get the necessary information to use Cloud Storage through JSON API. These are the following three items.

  • Client ID
  • Redirect URL
  • Scope

Please refer to "How to get Google Client ID and Client Secret?" if you do not have any idea to get them. Additionally, please make the "OAuth consent screen." Please select the appropriate scope according to "
Cloud Storage authentication"
.

Get Access Token (Source Code and Result)

This section shows the source code that gets access token only. It provides the function to get an access token through the OAuth consent screen when the user clicks the "Get Access Token" button.

Source Code

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <script type="text/javascript" src="/index.js" defer></script>
  </head>
  <body>
    <button onclick="oauthSignIn()">Get Access Token</button>
    <form id="formElem">
      <input type="file" id="file-upload" name="file-upload" />
      <input type="submit" id="submit-button" disabled />
    </form>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

index.js

/**
 * Extract the access token from the URL
 */
for (value of location.hash.split("&")) {
  if (value.indexOf("access_token=") === 0) {
    const access_token = value.split("=")[1];
    const ele = document.createElement("p");
    ele.textContent = "Your access token is '" + access_token + "'.";
    document.body.appendChild(ele);
  }
}
/**
 * The following source code is from the page.
 * https://developers.google.com/identity/protocols/oauth2/javascript-implicit-flow#oauth-2.0-endpoints
 */
/*
 * Create a form to request an access token from Google's OAuth 2.0 server.
 */
function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = "https://accounts.google.com/o/oauth2/v2/auth";

  // Create <form> element to submit parameters to OAuth 2.0 endpoint.
  var form = document.createElement("form");
  form.setAttribute("method", "GET"); // Send as a GET request.
  form.setAttribute("action", oauth2Endpoint);

  // Parameters to pass to OAuth 2.0 endpoint.
  var params = {
    client_id: [Client ID you set up before section],
    redirect_uri: [Refirect URL you set up before section, for example, "http://localhost:3000"],
    response_type: "token",
    scope: [Scope you set up before section, for example, "https://www.googleapis.com/auth/devstorage.read_write"],
    include_granted_scopes: "true",
    state: "pass-through value",
  };

  // Add form parameters as hidden input values.
  for (var p in params) {
    var input = document.createElement("input");
    input.setAttribute("type", "hidden");
    input.setAttribute("name", p);
    input.setAttribute("value", params[p]);
    form.appendChild(input);
  }

  // Add form to page and submit it to open the OAuth 2.0 endpoint.
  document.body.appendChild(form);
  form.submit();
}

Enter fullscreen mode Exit fullscreen mode

Result

Get the access token

Upload Files to Cloud Storage (Source Code and Result)

This section shows how to upload files to Cloud Storage using the access token you get in the previous section. You need to make a new bucket on Cloud Console. If you don't know how to make it, please refer to "Create storage buckets".

Source Code

The HTML file is the same as before. Please fix the Javascript source code as the following.

index.js

const bucketName = [Bucket name you made];
const clientID = [Client ID you set up];
const redirectURL = [Redirect URL];
const scope = [Scope];
let accessToken = null;

/**
 * Extract the access token from the redirect URL
 */
for (value of location.hash.split("&")) {
  if (value.indexOf("access_token=") === 0) {
    const access_token = value.split("=")[1];
    const ele = document.createElement("p");
    ele.textContent = "Your access token is '" + access_token + "'.";
    accessToken = access_token;
    document.body.appendChild(ele);
    document.getElementById("submit-button").disabled = false;
  }
}

/**
 * Upload file
 */
formElem.onsubmit = async (e) => {
  e.preventDefault();
  const file = document.getElementById("file-upload");
  const filename = file.value.split("\\").slice(-1)[0];
  console.log("File Name: " + JSON.stringify(filename));
  const extension = filename.split(".").slice(-1)[0].toLocaleLowerCase();
  let contentType = null;
  // Detect Content Type
  if (extension === "png") {
    contentType = "image/png";
  } else if (extension === "jpg" || extension === "jpeg") {
    contentType = "image/jpeg";
  } else if (extension === "svg") {
    contentType = "image/svg+xml";
  } else if (extension === "mpeg") {
    contentType = "video/mpeg";
  } else if (extension === "webm") {
    contentType = "video/webm";
  } else {
    alert("This file is invalid.");
  }
  // Load file and upload it
  if (contentType) {
    const reader = new FileReader();
    reader.addEventListener("load", async (event) => {
      const bytes = event.target.result;
      let response = await fetch(
        `https://storage.googleapis.com/upload/storage/v1/b/${bucketName}/o?uploadType=media&name=${filename}`,
        {
          method: "POST",
          headers: {
            "Content-Type": contentType,
            Authorization: `Bearer ${accessToken}`,
          },
          body: bytes,
        }
      );

      let result = await response.json();
      if (result.mediaLink) {
        alert(
          `Success to upload ${filename}. You can access it to ${result.mediaLink}`
        );
      } else {
        alert(`Failed to upload ${filename}`);
      }
    });

    reader.readAsArrayBuffer(file.files[0]);
  }
};

/**
 * The following Source code originated from https://developers.google.com/identity/protocols/oauth2/javascript-implicit-flow#oauth-2.0-endpoints
 */
/*
 * Create a form to request an access token from Google's OAuth 2.0 server.
 */
function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = "https://accounts.google.com/o/oauth2/v2/auth";

  // Create <form> element to submit parameters to OAuth 2.0 endpoint.
  var form = document.createElement("form");
  form.setAttribute("method", "GET"); // Send as a GET request.
  form.setAttribute("action", oauth2Endpoint);

  // Parameters to pass to OAuth 2.0 endpoint.
  var params = {
    client_id: clientID,
    redirect_uri: redirectURL,
    response_type: "token",
    scope: scope,
    include_granted_scopes: "true",
    state: "pass-through value",
  };

  // Add form parameters as hidden input values.
  for (var p in params) {
    var input = document.createElement("input");
    input.setAttribute("type", "hidden");
    input.setAttribute("name", p);
    input.setAttribute("value", params[p]);
    form.appendChild(input);
  }

  // Add form to page and submit it to open the OAuth 2.0 endpoint.
  document.body.appendChild(form);
  form.submit();
}
Enter fullscreen mode Exit fullscreen mode

Result

The result to upload file

I list references in the following.

  • MIME Types

MIME types (IANA media types) - HTTP | MDN

A media type (also known as a Multipurpose Internet Mail Extensions or MIME type) indicates the nature and format of a document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838.

favicon developer.mozilla.org
  • upload file to Cloud Storage using curl

Upload objects ย |ย  Cloud Storage ย |ย  Google Cloud

Describes options for uploading objects to a Cloud Storage bucket. An object consists of the data you want to store along with any associated metadata. You can upload objects using the supplied code and API samples.

favicon cloud.google.com
  • fetch usage

Using the Fetch API - Web APIs | MDN

The Fetch API provides a JavaScript interface for accessing and manipulating parts of the HTTP pipeline, such as requests and responses. It also provides a global fetch() method that provides an easy, logical way to fetch resources asynchronously across the network.

favicon developer.mozilla.org
  • <input type="file"> usage

    Using files from web applications - Web APIs | MDN

    Using the File API, which was added to the DOM in HTML5, it's now possible for web content to ask the user to select local files and then read the contents of those files. This selection can be done by either using an HTML <input type="file"> element or by drag and drop.

    favicon developer.mozilla.org

    <input type="file"> - HTML: HyperText Markup Language | MDN

    <input> elements with type="file" let the user choose one or more files from their device storage. Once chosen, the files can be uploaded to a server using form submission, or manipulated using JavaScript code and the File API.

    favicon developer.mozilla.org

The original article is the following. This article was translated from Japanese to English.

Top comments (0)

Need a better mental model for async/await?

Check out this classic DEV post on the subject.

โญ๏ธ๐ŸŽ€ JavaScript Visualized: Promises & Async/Await

async await