What's?

Home / Instagram API を AWS API Gateway でWrappingして、node環境からCognitoを使って叩く方法

Instagram API を AWS API Gateway でWrappingして、node環境からCognitoを使って叩く方法
March 03, 2018

DEVELOPMENT

web
js
aws
api-gateway
lambda
cognito
node
instagram

S3、Cloudfrontにてwebサイトを公開してますが、jsからSNS(ここではInstagram)のAPIを使用する際、気になるのがAccess token。

Access token をパラメータに含みたくないので、AWSのAPI gatewayでラッピングして、使用するようにしました。

更にそのAPIをAWS_IAM認証制限し、Cognitoを使って node 環境から叩く方法についてメモしておこうと思います。

各種必要なAPIの準備

僕は今回InstagramのAPIを叩きたかったので、下記を参考にdeveloper登録をして、access tokenを取得してAPIを叩けるようにしました。

Instagram APIを使ってWebページに表示する

Instagram Developer

API Gatewayの設定

処理の流れとしては下記です。

  1. API Gateway を叩く
  2. API GatewayからLambda関数が呼ばれる
  3. Labda関数が、必要なパラメータ等の処理をして、Instagram APIを叩く
  4. レスポンス返却

それではAPI Gatewayを設定していきます。

AWSコンソールにログイン -> API Gatewayへ -> APIの作成をクリック

API作成

リソースの作成

API自体が作成されたので、次にリソースを作成します。 アクション -> リソースを作成 を選択します。 API作成3

  • リソース名
  • API Gateway CORSを有効にするにチェック

メソッドの作成

作成されたリソースを選択した状態で、アクション -> メソッドの作成を選択します。

API作成4

セレクトボックからGETを選択し、チェックマークをクリック

ただAPIを叩くラッピングするだけなら、ここで統合タイプをHTTPを選択し、エンドポイントにそのAPIを指定すればOKですが、ただ、client から渡ってきた Query String を endpoint に渡す際、key は変更できるものの、value を変えたり、特定の key を静的に(=固定で)指定といったことはできないようですので、今回はLambda関数を使用します。

API作成5

今回はAccess tokenを静的に渡したいので、lambda関数を使用します

API Gateway + Lambda で固定のパラメータを付加して HTTP Proxy する

クエリパラメータの設定

今回はinstagram api で投稿データを数軒取得しましたが、全件取得しても無駄なので、必要な件数のみ取得しようと思います。Instagra api 側で countというクエリパラメータがあるので、これをAPI gatewayで設定したAPIにも付加できるように設定します。 API作成6 GETメソッドを選択状態にし、「メソッドリクエストから」クエリ文字列の追加から、クエリ名を入力します。


次に「統合リクエスト」から一番下***本文マッピングテンプレート***から、追加し、content-typeを「application/json」に設定し下記のように設定します。

API作成65

※、ダブルクォートで囲わないとうまく行きません。


ここまでで、一旦API Gatewayの設定は終わりです。後に、deployとアクセスの制限の設定をします。 次にLambda関数を準備します。

Lambda関数の設定

関数の作成

AWSコンソールより、Lambdaを選択し、関数の作成をクリック

Lambda

トリガーの設定

トリガーを追加します。

Lambda2


関数のコード作成

今回はnode.jsを使います。 local環境にて、

$ yarn init

もしくは

$ npm init

し、projectを作成します。

必要なパッケージを入れます。

$ yarn add requrest

もしくは

$ npm install request --save

jsファイルを作成します。

  • index.js
var request = require('request');
exports.handler = function(event, context) {
  var params = { count:event.count, access_token: process.env.ACCESS_TOKEN};

  request.get({url:process.env.URL, qs: params}, function(err, res, body) {
    if (!err && res.statusCode == 200) {
      context.done(null, body);
    } else {
      console.log('error: '+ res.statusCode);
    }
  });
};
  • process.envは、後ほどLambda 側で設定します。
  • 単純に、requestを使って、APIを叩く処理です。
  • event.countは先程API Gatewayで設定した、クエリパラメータになります。

次にこれら(index.jsと作成されたnode_modulesの2つ)をLambdaにアップロードするために、zipで圧縮します。

アップロードします。 Lambda3

環境変数を設定

コード中のprocess.envの値を設定します。 Lambda4

これでLambdaの設定は以上になります。

API Gatewayをdeployする

デプロイ

AWSコンソールにログイン -> 再びAPI Gatewayへ -> APIの作成をクリック 先程作成した、APIを選択します。

API ルートを選択し、アクションから、APIのデプロイを選択 API作成7

エンドポイントの確認

左メニューのステージを選択する API作成8

ここまでで、APIのラッピング作業は終わりです。実際に表示されているURLを叩いて結果が帰ってくればOKです。 設定した、クエリパラメータ(count)も指定してみましょう。

これでOKですが、APIのURLがバレたら誰でも叩けてしまうのはちょっと嫌なので(jsから使うため)、Cognitoを使って制限します。

API Gatewayに認証をつける

AWSコンソールにログイン -> 再びAPI Gatewayへ -> APIの作成をクリック 先程作成した、APIを選択します。 API作成9 GET を選択し、認証をAWS_IAMに設定します。

これで先程と同じようにデプロイし、エンドポイントに表示されているURLをたていてもデータを取得できないことを確認します。

ARNのメモ

API Gatewayの画面で、ARNをメモしておきます。 API作成10


Cognitoの設定

プールIDの作成

AWSコンソールにログイン -> Cognitoへ -> フェデレーテッドアイデンティティの管理を選択 -> 新しい ID プールの作成 Cognito プールIDを作成します


ポリシーの設定

Cognito2 ポリシードキュメントを下記のように設定します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "execute-api:Invoke"
      ],
      "Resource": [
        "arn:aws:execute-api:xx-xxxx-xx:xxxxxxxxxxxx:xxxxxxxxxx/*/GET/instagram"
      ]
    }
  ]
}
  • Resource部分は、execute-api:リージョン:arn-idになります。先程メモった内容です。

jsコードを取得

Cognito3

これでcognitoの設定はOKです。


Node 環境から実際に使ってみる

AWS API Gateway は便利なサービスですが、Node.js から使おうとすると、自動で生成される JavaScript のSDKがブラウザ用しか用意されていなかったり、エンドポイントごとにメソッドが自動で生成されていて、APIのエンドポイントを変更するごとにSDKを生成し直さなければならなかったりと不便だったため、Node.js から API Gateway を簡単に使えるパッケージを作ってくれた方がいらっしゃいましたので、こちらを使用させていただきました。ありがとうございます。 Node.js から API Gateway を簡単に使えるパッケージ作りました

準備

$ yarn add aws-sdk
$ yarn add aws-api-gateway-client

もしくは

$ npm install add aws-sdk
$ npm install aws-api-gateway-client

※parcelを使っていますが、babelモジュール等の依存があるので、このパッケージで使っているモジュールを入れます

.babelrc

{
  "presets": [
    "stage-0",
    "@ava/stage-4",
    "babel-preset-es2015",
    "babel-preset-es2016",
    "babel-preset-es2017",
  ],
  "plugins": ["transform-es5-property-mutators"]
}

上記が必要なものですので、すべてnpm or yarnで入れます。各moduleについてはググれば出てきますのでお願いします。 2018/03 これは、babelrcに入れなくても、aws-api-gateway-clientに上記が必要なだけですので、install しておくだけでOKです。

$ yarn add --dev babel-plugin-transform-es5-property-mutators @ava/babel-preset-stage-4 babel-preset-stage-0 babel-preset-es2015 babel-preset-es2016 babel-preset-es2017

OR

$ npm install --save-dev babel-plugin-transform-es5-property-mutators @ava/babel-preset-stage-4 babel-preset-stage-0 babel-preset-es2015 babel-preset-es2016 babel-preset-es2017

コード

import AWS from 'aws-sdk'

let apigClientFactory = require('aws-api-gateway-client').default

// Amazon Cognito
AWS.config.region = 'xxxxxxxxxxx'
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
  IdentityPoolId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
})

AWS.config.credentials.get(function(err){
  if(!err) {
    const apigClient = apigClientFactory.newClient({
      accessKey: AWS.config.credentials.accessKeyId,
      secretKey: AWS.config.credentials.secretAccessKey,
      sessionToken: AWS.config.credentials.sessionToken,
      region: 'xxxxxxxx',
      invokeUrl: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    });
    let params = {
       //This is where any header, path, or querystring request params go. The key is the parameter named as defined in the API
    };
    // Template syntax follows url-template https://www.npmjs.com/package/url-template
    let pathTemplate = 設定したAPIのパス
    let method = 'GET'
    let additionalParams = {
      //If there are any unmodeled query parameters or headers that need to be sent with the request you can add them here
      queryParams: {
        count: 必要な件数,
      }
    };
    let body = {
      //This is where you define the body of the request
    };

    let items = []
    apigClient.invokeApi(params, pathTemplate, method, additionalParams, body)
      .then(function(result){
        // 成功処理
      }).catch( function(result){
        //This is where you would put an error callback
        // エラー処理
      });
    }else{
      console.log(err)
    }
  }
})

以上です。

まとめ

これで安全にAPIを叩くことができるようになりました。 意外とnode環境からAPI gatewayを叩くすべがあまりなく、たまたま作ってくださっていた方がいらっしゃいましたので、助かりました。 ありがとうございました。

うかい / 株式会社UKAI
うかい@代表取締役兼エンジニア株式会社UKAI
Nobuyuki Ukai

株式会社UKAI 代表取締役CEO。建築を専攻していたが、新卒でYahoo!Japanにエンジニアとして入社。その後、転職、脱サラ、フリーランスエンジニアを経て、田舎へ移住し、ゲストハウスの開業、法人成り。ゲストハウス2軒、焼肉店、カフェ、食品製造業を運営しています。詳細はこちらから

🙏よかったらシェアお願いします🙏
WRITTEN BY
うかい / 株式会社UKAI
うかい@代表取締役兼エンジニア株式会社UKAI

Nobuyuki Ukai

株式会社UKAI 代表取締役CEO。建築を専攻していたが、新卒でYahoo!Japanにエンジニアとして入社。その後、転職、脱サラ、フリーランスエンジニアを経て、田舎へ移住し、ゲストハウスの開業、法人成り。ゲストハウス2軒、焼肉店、カフェ、食品製造業を運営しています。詳細はこちらから

CONACT
入力して下さい
Slack からもどうぞ

※お気軽にどうぞ!(6月20日まで有効!お早めに)

COPYRIGHT © 2020 UKAI CO., LTD. ALL RIGHTS RESERVED.