【AWS】Amplify使ってAPI Gatewayにリクエスト送信したい

 

目的

  • AWS Amplifyを使用してAWS Gatewayに通信する

  • Amplifyコマンドは使わない。AWS SDK機能のみ使う

  • 実装はAngular

  • Angular CLIの環境構築は実施済とする

 

<参考>

Amplify Docs

https://docs.amplify.aws/start/getting-started/installation/q/integration/angular

 

環境

NO 項目 バージョン
1 Angular 10.0.5
2 Amplify 3.3.4
3 Typescript 3.9.5

 

実装

Angularプロジェクトを作成

ng new ${プロジェクト名}

 

Amplifyライブラリを追加

npm install --save aws-amplify @aws-amplify/ui-angular

 

AWSの設定ファイルを作成

フォーマットはAmplifyコマンドで生成されてるものに合わせました。

 

aws-export.jsを作成

${プロジェクトルート}/src/aws-exports.js

import Amplify from 'aws-amplify';

// cognitoやS3に接続する設定を追記する箇所
const awsmobile = {
};

export default awsmobile;

// API Gatewayの設定
Amplify.configure({
 API: {
     endpoints: [
        {
             name: '${API名}',
             endpoint: '${エンドポイント}'
        }
    ]
}
});

 

API名は↓を設定。

f:id:kanmi-program:20201030234841p:plain



エンドポイントは↓を設定。

f:id:kanmi-program:20201030234850p:plain



 

設定ファイル読み込み処理を実装

app.module.tsに実装しました。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

// Amplifyと設定ファイルをインポート
import Amplify from 'aws-amplify';
import config from '../aws-exports';

// 設定ファイルを読み込ませる
Amplify.configure(config)

@NgModule({
 declarations: [
   AppComponent
],
 imports: [
   BrowserModule,
   AppRoutingModule
],
 providers: [],
 bootstrap: [AppComponent]
})
export class AppModule { }

 

Shimの追加

polyfills.tsにglobalとprocessのShimを追記する。

/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
*   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
*   2. Application imports. Files imported after ZoneJS that should be loaded before your main
*     file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/

/***************************************************************************************************
* BROWSER POLYFILLS
*/

/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.

/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.

/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/

/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone';  // Included with Angular CLI.


/***************************************************************************************************
* APPLICATION IMPORTS
*/
// globalとprocessのShimを追記
(window as any).global = window;
(window as any).process = {
   env: { DEBUG: undefined },
};

 

リクエスト送信処理の実装

 

GET通信の場合

import { Component } from '@angular/core';
import { from } from 'rxjs';

// amplifyをインポート
import { API } from 'aws-amplify';

@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.scss'],
})
export class AppComponent {
 title = 'AmplifyTest';

 /**
  * API Gatewayに通信する
  */
 sendRequest() {
   const apiName = '${API名}';
   const path = '${APIパス}';
   const init = {
     // クエリパラメータを設定
     queryStringParameters: {
       orderId: '1234',
    },
     // ヘッダーを設定
     headers: {
       'Content-Type': 'application/json',
    },
  };

   // API実行
   // RXJSで扱いたいためPromiseをfromで変換
   from(API.get(apiName, path, init)).subscribe(
    (result) => {
       console.log(result);
    },
    (error) => {
       console.log(error);
    }
  );
}
}

※CORSでエラーが出る場合(1)を参照

 

POST通信の場合

import { Component } from '@angular/core';
import { from } from 'rxjs';

// amplifyをインポート
import { API } from 'aws-amplify';

@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.scss'],
})
export class AppComponent {
 title = 'AmplifyTest';

 /**
  * API Gatewayに通信する
  */
 sendPOSTRequest() {
   const apiName = 'TestLambda-API';
   const path = '/history';
   const init = {
     // ボディを追加
     body: {
       name: 'taro',
       order: '醤油マシマシ',
       date: '2020-10-11',
    },
     // ヘッダーを追加
     headers: {
       'Content-Type': 'application/json; charset=utf-8',
    },
  };

   // API実行
   // RXJSで扱いたいためPromiseをfromで変換
   from(API.post(apiName, path, init)).subscribe(
    (result) => {
       console.log(result);
    },
    (error) => {
       console.log(error);
    }
  );
}
}

※CORSでエラーが出る場合(1)を参照

 

 

その他

(1)CORSでエラーになる

①CORSを適用したいAPIに以下のパスを追加する。

No 項目
1 パス {proxy+}
2 メソッド OPTIONS

 

②追加したパスに適当なLambdaを統合する。

※ドキュメントにCORSのレスポンスが記載されているがAPI Gateway V2の場合無視されるので、

 左メニュー「開発」→「CORS」で設定する。

 

Lambda

※初期状態でもOK

import json

def lambda_handler(event, context):
   # TODO implement
   return {
       'statusCode': 200,
       'body': json.dumps('Hello from Lambda!')
  }

 

CORS

f:id:kanmi-program:20201030234856p:plain

 

<参考>

REST API リソースの CORS を有効にする

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-cors.html

 

Angular HttpInterceptorを使いたい

AmplifyはHTTPクライアントにAxiosを使用しているためAngularのInterceptorが使用できない