1
Help us understand the problem. What are the problem?

posted at

updated at

GoogleAPIを実行してデータを取得するAPIをAWSのLambdaとAPI Gatewayでつくる

記事の概要

非公開のGoogleスプレッドシートの情報を取得する関数をLambdaで作成
API Gatewayで呼び出すところまでの手順を記録

  • 利用サービス
    • Google Cloud APIs
    • AWS Lambda
    • AWS API Gateway

前提

  • javascriptで何かしらの開発した経験がある
  • Google Cloud Platformアカウントを所持している
  • AWSアカウントを所持している

作業手順目次

  1. Google Cloud APIs
    1. プロジェクトの作成
    2. Google Sheets API ライブラリの有効化
    3. 認証情報の追加
    4. 鍵の作成
  2. Lambda
    1. 関数の作成
    2. node_modulesのLayers登録
    3. 環境変数の登録(Googleの認証情報)
  3. API Gateway
    1. APIの作成
    2. リソースの作成
    3. メソッドの作成
    4. APIのデプロイ
    5. 制限の設定
  4. APIの呼び出し
    1. サンプルコード

Google Cloud APIs

Google Cloud Platform
Googleが提供しているクラウドコンピューティングサービス
Google Cloud APIsの利用にはこのアカウントが必要

Google Cloud APIs
Googleが提供するサービスのデータを操作することができるAPIを
インターネットを通じて実行できるサービス

プロジェクトの作成

report_2022-01-03-02.png
report_2022-01-03-03.png

ライブラリの有効化

プロジェクトで利用するAPIを有効化する

  1. APIとサービス > ライブラリ
  2. Google Sheets APIを選択
  3. 有効にする

report_2022-01-03-05.png
report_2022-01-03-06.png
report_2022-01-03-07.png

認証情報の追加

1. APIとサービス > 認証情報

  1. 認証情報を作成 > サービスアカウント
  2. アカウント名の入力 > 完了

report_2022-01-03-09.png
report_2022-01-03-10.png
report_2022-01-03-11.png
report_2022-01-03-12.png
report_2022-01-03-13.png

鍵の作成

Lambdaで利用するための認証鍵の作成

  1. サービスアカウントの詳細 > キー > 鍵の作成
  2. キータイプ JSON > 作成
  3. jsonがダウンロードできる(あとで内容をLambdaに登録する)

report_2022-01-03-14.png
report_2022-01-03-15.png
report_2022-01-03-16.png
report_2022-01-03-17.png

AWS Lambda

AWS(Amazon Web Services)
Amazon.comにより提供されているクラウドコンピューティングサービス

Lambda
サーバーレスで開発したプログラムを実行できるようにするサービス

関数の作成

  • [関数名] sample-test(任意の名前でOK)
  • [作成方法] 一から作成
  • [ランタイム] Node.js 14.x
  • [アーキテクチャ] x86_64

report_2022-01-03-20.png
report_2022-01-03-21.png
report_2022-01-03-22.png

新規作成直後のコード

exports.handler = async (event) => {
    // TODO implement
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

node_modulesのLayers登録

AWS Lambda Layers
複数のLambda関数で外部ライブラリなどを共有できる仕組み

Lambdaでは、ファイル量が多いとブラウザ操作が制限されるため
node_modulesを含めたコードソースをZIPで登録した場合
ブラウザ上で関数の編集や閲覧ができなくなる

この状態は関数作成時に不便なため
使っているnode_modulesをAWS Lambda Layersに登録することで回避する

登録したレイヤーは関数の「レイヤー」に追加して利用できる
また、他の関数作成時にも同じレイヤーを利用することができる

  1. レイヤーの一覧 > 作成
  2. node_modules(以下package.jsonをローカルで展開し)をzipにしてアップロード
  3. レイヤーの追加

package.json

{
  "dependencies": {
    "googleapis": "^92.0.0"
  }
}

report_2022-01-03-24.png
report_2022-01-03-25.png
report_2022-01-03-26.png
report_2022-01-03-27.png
report_2022-01-03-28.png

環境変数の登録

  1. 関数の詳細 > 設定 > 環境変数
  2. 環境変数の編集 で 「環境変数の追加」を押す
  3. aキー名 と 値 を入力 し保存

report_2022-01-03-30.png
report_2022-01-03-31.png
report_2022-01-03-32.png

GoogleAPIからデータを取得して返すコードの作成

// レイヤー_登録したnode_modulesにgoogleapisを含めている前提
const { google } = require('googleapis');
const sheets = google.sheets('v4');

// 登録した環境変数の取得
const SERVICE_ACCOUNT_KEY = JSON.parse(process.env.SERVICE_ACCOUNT_KEY);

// 外部ドメインからAPIを叩くのでクロスドメインの許可
const HEADERS = {
  "Access-Control-Allow-Headers" : "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token",
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "OPTIONS,POST,GET"
};

async function execAPI(spreadsheetId, range) {
  // 利用するAPIは Google spreadsheetsの情報を取得するspreadsheets
  const auth = await google.auth.getClient({
    credentials: SERVICE_ACCOUNT_KEY,
    scopes: ['https://www.googleapis.com/auth/spreadsheets'],
  });

  const apiOptions = {
    auth,
    spreadsheetId,
    range,
  };

  return sheets.spreadsheets.values.get(apiOptions);
}

exports.handler = async (event) => {
  // event?.pathParameters でAWS API Gatewayで作成したパスパラメータを取得
  const spreadsheetId = event?.pathParameters?.spreadsheetId;
  const range = event?.pathParameters?.range ? decodeURI(event?.pathParameters?.range) : 'シート1';

  let response = {};
  let responseBody = {}
  await execAPI(spreadsheetId, range).then((t) => {
    responseBody = t;
  })
  // getメソッドとして返す場合のオブジェクト形式
  response = {
    "statusCode": 200,
    "body": JSON.stringify(responseBody),
    "headers": HEADERS,
  };
  return response;
};

AWS API Gateway

Lambdaで作成した関数を呼び出せるREST APIの作成を行う

AWS API Gateway
簡単にAPIの作成、配布、保守、監視、保護が行えるマネージドサービス

  1. APIの作成
  2. リソースの作成
    1. API Gateway CORSを有効にする
  3. メソッドの作成
  4. APIのデプロイ
  5. 制限の設定

APIの作成

  1. APIの作成
  2. REST APIを構築
  3. API > 作成
    • [プロトコル] REST
    • [新しいAPIの作成] 新しいAPI
    • [API名] 半角英数字
    • [エンドポイント] リージョン

report_2022-01-03-34.png
report_2022-01-03-35.png
report_2022-01-03-36.png

リソースの作成

  • リソースの作成
    • /test
      • /{spreadsheetId}
        • /{range}
        • API Gateway CORSを有効にする

report_2022-01-03-37.png
report_2022-01-03-38.png
report_2022-01-03-39.png

メソッドの作成

  • メソッドの作成 > GET
  • Lambda関数を実行します

report_2022-01-03-40.png
report_2022-01-03-41.png
report_2022-01-03-42.png
report_2022-01-03-43.png

APIのデプロイ

作ったAPIを公開する

  • プロシキの統合
    • クロスドメインで実行できるようにするため
  • アクション > APIのデプロイ
  • レートの変更
    • 必要に応じて安全なレートに変更する
    • レート 10、バースト 5 は1ヶ月呼び出され続けても一万円ほどでおさまる想定の値

report_2022-01-03-45.png
report_2022-01-03-46.png
report_2022-01-03-47.png

制限の設定

セキュリティを考慮して呼び出し処理に制限をかける

  • APIキーがなければ呼び出せない
  • APIキーを使っていても設定したプラン以上の呼び出しは行えない

手順

  • APIキーの追加
  • 使用量プランの作成
    • APIステージの追加
    • APIキーを使用プランに追加
  • APIキーに使用料プランの設定

report_2022-01-03-49.png
report_2022-01-03-50.png
report_2022-01-03-51.png
report_2022-01-03-53.png
report_2022-01-03-54.png

APIの呼び出し

サンプルコード

<html>
<header>
  <script>
    function getLocalApi() {
      const sheetId = document.getElementById('sheetId').value;
      const range = document.getElementById('range').value || 'シート1'; 
  
      const request = new XMLHttpRequest()
      request.open('GET', `https://[ドメイン]/[ステージ名]/test/${sheetId}/${range}`)
      request.setRequestHeader('Content-Type', 'application/json');
      request.setRequestHeader('x-api-key', '[APIキー]');
      request.responseType = 'json'
      request.send();

      request.onerror = function(e){
        console.log(e);
        alert('データが取得できませんでした');
      };

      request.onload = () => {
        if (request.status === 200) {
          console.log(request.response);
          alert('データが取得できました');
        }
      };
    }
  </script>
</header>
<body>
  <input type="text" id="sheetId" name="sheetId" size="20" value=""  placeholder="sheetId" required>
  <input type="text" id="range" name="range" size="20" value="" placeholder="range" required>

  <hr  style="margin-top: 20px;">

  <button type="button" onclick="getLocalApi()">
    サービスアカウントからデータ取得
  </button>
</body>
</html>

コードに必要な ドメイン / ステージ名 / APIキー は以下の画面から取得

report_2022-01-03-56.png

実行テスト

  1. スプレッドシートを作成
  2. Googleサービスアカウントユーザーを編集者に追加
  3. スプレッドシートのシートIDで実行して取得完了!

report_2022-01-03-57.png
report_2022-01-03-58.png

まとめ

外部サービスからGoogleのデータを取得できないか模索したところ
AWSについて教えてもらい、この機会に資料にまとめた。
クロスブラウザが可能な外部サービスであれば色んな面白いことができそう。

次回はこれを利用して作成したFigmaプラグインについてまとめる。

参考

GoogleAPI

GoogleAPIをフロントで呼び出す時のサンプルコード

GoogleSheetsAPIのGETエンドポイントサンプルコード

使ってないけどリダイレクトでAuth認証するための方法

APIGateway

Lambda プロキシ統合の使用って何??

APIGatewayでクロスオリジンのためのOption関数を設定する話

APIGatewayでパスパラメータを設定する方法

APIGatewayのAPIキー設定する方法

Lambda

Lambda関数のレスポンスの形式を正しく渡さないとクロスオリジン解決できないよって話の参考

Lambda関数のレスポンスの形式を正しく渡さないとAPIGatewayから怒られる話

Lambdaで環境変数を使う方法

Lambdaでnode_modulesもzipにしてアップロードしないといけなかった話

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
1
Help us understand the problem. What are the problem?