カテゴリー
JavaScript

Chrome Extensions v3からGoogle Drive APIを操作する

Manifest v2とv3ではだいぶ実装方法が異なるようで、Web上にはv3の情報が少なかったため、最小実装の方法を調べて実装してみました。

(結局、Query Stringをどう書くのかを調べるのが一番大変だった、、というAPIあるある、、でしたがw)

AuthTokenをゲットする方法は前回のpostを参照ください。

fileをGoogle Drive内の特定のParentフォルダ内に作成するには以下のコードを使います。変数parentはファイルidです。

ちなみにGoogle Driveではfolderとfile、どちらもfileとして扱い、mimeTypeによって区別されます。

公式DocumentによるとSheets APIは現時点では特定のフォルダにspreadsheetを作成することができないため、作成後にファイルを移動するか、Drive APIを使用します。

また、このようなネットワーク通信などのAsynchronous(非同期)な処理はPromiseを使って、コールする時にasync/awaitできるようにしておくと勝手が良いです。

// using Drive API
function createSpreadsheet(token, parent, fileName) {
  return new Promise((resolve, reject)=>{
    const fileMetadata = {
      "name" : fileName,
      "mimeType" : "application/vnd.google-apps.spreadsheet",
      // by specifying the parents, the API will create the file in that folder
      "parents" : [parent]
    }
    fetch("https://www.googleapis.com/drive/v3/files", {
      method: "POST",
      headers: {
        "Content-Type" : "application/json", 
        "Authorization" : `Bearer ${token}`
      },
      body: JSON.stringify(fileMetadata)
    }).then((document)=>{
      return document.json();
    }).then(async (result)=>{
      menus[result.name] = result.id;
      await initialSetupOfSheet(token, result.id);
      resolve();
    }).catch((error)=>{
      console.log("in createSpreadsheet: ", error);
      reject(error);
    });
  });
}

以下は、ファイル名でサーチするコード。

ちなみに、Google Drive APIではsearch query部分を以下のようにq=mimeType=とし、また、’application/vnd.google-apps.spreadsheet’とクォートで囲まなければ認識しないようで、URLSearchParamsをすんなりと使わせてくれなかったためこのようにしています。

function getFileByName(token, fileType, fileName) {
    fetch(`https://www.googleapis.com/drive/v3/files?fields=files(name,id,kind,mimeType,trashed)&q=mimeType='application/vnd.google-apps.${fileType}'+and+name+contains+'${fileName}'`, {
      method: "GET",
      headers: { 
        "Authorization" : "Bearer " + token,
      },
      // can't have body in this method
    }).then((response) => {
      return response.json();
    });
}

Parentフォルダ内のファイルをゲットするコード

function getTheFilesOrCreateIfNone(token, fileId){
  return new Promise((resolve, reject)=>{
    fetch(`https://www.googleapis.com/drive/v3/files?q="${fileId}"+in+parents&mimeType='application/vnd.google-apps.spreadsheet'&fields=files(name,kind,id,mimeType,trashed)`, {
      method: "GET",
      headers: {
        "Authorization": "Bearer " + token
      },
    }).then((result)=>{
      console.log("checking if working: ", result);
      return result.json();
    }).then(async (result)=>{
    // do what ever...
      console.log(result.files);
      console.log("files including in trash: ", result.files.length);
      let files = result.files.filter((file)=>{
        return file.trashed == false;
      })
      // if there is (are) spreadsheet(s), set the context menu
      if (files.length > 0) {
        for (const file of files) {
          menus[file.name] = file.id;
        }
      } else {
        // create new spreadsheet called "Words" in the app folder
        await createSpreadsheet(token, _folderId, "Words");
      }
      // success
      setMenus();
      resolve();
    }).catch((error)=>{
      // fail
      reject(error);
    });
  });
}

Spreadsheetにデータを挿入するためのコード

function writeToSheet(token, fileId, text, context, url) {
  console.log("writing data to the sheet");
  return new Promise((resolve, reject) => {
    const range = "A1:E1";
    const date = Date();
    const bodyData = {
      "range" : range,
      "majorDimension" : "ROWS",
      "values" : [
        [text, context, "", url, date]
      ]
    };
    fetch(`https://sheets.googleapis.com/v4/spreadsheets/${fileId}/values/${range}:append?insertDataOption=INSERT_ROWS&valueInputOption=RAW`, {
      method: "POST",
      headers: {
        // Content-Type is needed, otherwise "parse error"
        "Content-Type" : "application/json", 
        "Authorization" : `Bearer ${token}`
      },
      body: JSON.stringify(bodyData),
    }).then((response) => {
      return response.json();
    }).then((response) => {
      console.log(response);
      resolve();
    }).catch((error) => {
      console.log(error);
      reject("in writeToSheet", error);
    });
  });
}