[Angular x AWS SDK for JavaScript] SPAからAWSのデータを取得する際の待ち合わせ処理(非同期処理)

  • SPAのプラットフォームにAWSを採用した際によく書くロジックについてのメモ

    • ex. クライアントからs3 bucketのobjectを取得して画面に表示
  • AWS SDKでデータを取得するまではディベロッパーガイドを見れば容易だが、待ち合わせ処理の書き方が少し面倒

前提知識


実装例

AWS SDK for JavaScript

  • 想定する状況

    • Angularのコンポーネント生成時(画面遷移時)に自動でAWS(S3)から情報を取得して画面に表示する
  • AWSからデータを取得して値を取り出すまでを待ち合わせ処理にする例

    1. ComponentからServiceのロジックを呼び出す
    2. Service内でAWSからデータを取得
      • 変数 = new Promise() の形式で、AWSへ問い合わせるロジックを書く
        • resolve(data)で変数に返り値を格納
      • 各関数間の待ち合わせ処理は async/await で実現する
    3. Promise型の返り値をComponentへ返す
    4. Component側で forkJoin().subscribe を使って受け取る
      .then()で受け取ってもOK (Angularでは基本subscribeが推奨されている)

書き方は他にもあるかも

AWS SDKを導入するまで

sampleの構成

  • request.service.ts

    • AWSとの通信用のService
  • sample.component.ts

    • Serviceを呼び出し、返り値を受け取るComponent
  • sample.component.html

    • 取得したデータを表示する

AWSへリクエストするService

以下の様に書かないと、データが帰ってくる前にcomponentにundefinedを返してしまう

  • AWSへのリクエストからの待ち合わせで返り値を取り出す方法

    • Promiseの中でリクエストする
    • GETしたデータをresolve()で返す
    • resolveで返された値をreturn
  • async/await でService内の各関数間の待ち合わせ処理を実現する

  • Service記載例 (request.service.ts)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    import { Injectable } from '@angular/core';

    // aws-sdkを変数AWSとしてimportする必要がある
    import * as AWS from 'aws-sdk'

    @Injectable({
    providedIn: 'root'
    })

    export class requestService {
    constructor() { }

    // 1. Componentから呼び出される関数
    async getAwsData() {
    return await this.requestData();
    }

    // 2. AWSに対してリクエストする関数
    async requestData() {

    // 変数requestに返り値を格納 待ち合わせのためにPromiseを用いる
    const request = new Promise((resolve, reject) => {

    // AWS SDKサービスのオブジェクトを宣言
    let bucket = new AWS.S3(({params: {Bucket: 'myBucket'}});

    // リクエストを実行 基本的に以下の様にdataに返り値が入る
    bucket.listObject(({}, (err, data ) => {
    if (err) {
    let errorMessage = String(err);
    alert(errorMessage);
    }
    else {
    // resolveでPromiseの処理を終了させる
    resolve(data); // データ加工が必要であれば、ここで関数を呼び出す
    }
    });
    });

    // エラーハンドリング
    request.catch((error) => {alert(error); } );
    // リクエスト結果を返す
    return request;
    }

    }
  • s3のデータの扱い方についてはディベロッパーガイドを参照。ここではあくまで共通した待ち合わせ処理の記法のみ


データを受け取るComponent側

  • Component側の受け取り方は2パターンある

    1. .then()
    2. .subscribe()
  • Component側の実装例(sample.component.ts)

    • serviceを呼び、データを受け取る
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//rxjs 待ち合わせ処理に必要
import { forkJoin } from 'rxjs';

let awsData; //データ受取用の変数を宣言

// 起動時に取得 → ngOnInitから呼び出す
ngOnInit() {
getData();
}

getData() {

// Credential認証 Service側でもいいかも
AWS.config.credentials = new AWS.Credentials("<access key>","<secret key>")

// thenで受け取る例
this.requestService.getAwsData().then(response =>{
console.log(response);
this.awsData = response; // 取得データを代入
});

// subscribeで受け取る例 Promise型のため、forkJoinが必要
forkJoin(this.grequestService.getAwsData()).subscribe(result => {
this.awsData = result[0]; // 取得データを代入
});
}
  • sample.compoent.html 取得したデータを画面に表示
    1
    {{getAwsData}}

参考

関連記事

その他

AWS SDK for JavaScriptでRegionリストを取得

やりたいこと

describeRegionsメソッド

  • 使用可能なリージョンに関する情報を取得するには、describeRegions メソッドを呼び出せばよい
    • 戻り値
      • Aws::EC2::Types::DescribeRegionsResult オブジェクト
        • DescribeRegionsResult.Regionsに配列が格納されている
        • AWS.EC2.RegionList
          1
          2
          3
          4
          console.log(data.Regions); // dataに戻り値が格納される
          [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
          console.log(data.Regions[0]);
          [object Object]
        • EC2.Region.RegionName
          1
          2
          console.log(data.Regions[0].RegionName);
          eu-north-1

実装例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// aws-sdkを変数AWSとしてimport
import * as AWS from 'aws-sdk';

// RegionListを取得するメソッド
getRegions() {
// AWS SDKのEC2オブジェクトを宣言
let ec2 = new AWS.EC2({region: ap-northeast-1}); // Default Regionの指定が必須
// 問合せ(describeRegions)を実行
ec2.describeRegions({}, (err, data ) => {
if (err) {
let errorMessage = String(err);
alert(errorMessage);
}
else { // データ取得時
// Aws::EC2::Types::DescribeRegionsResult オブジェクトが戻り値としてdataに格納される
let regions = data.Regions.map((d) => d.RegionName); // ループでリージョン名を抽出した配列を生成
return(regions);
}
});
}

参考

関連記事

その他

[AWS SDK for JavaScript] WEBアプリ→AWSへのリクエスト認証時のエラーハンドリング

  • WEBアプリ(Angular)からAWS SDK経由でAWSにアクセスする際に、Credential(AccessKey/SecretAccessKey)の認証が必須。そこでの認証エラーを検知する仕組みを作る手法についてのメモ

認証エラーを検知 → アラート発信 & 処理の中止

AWS SDK経由のリクエストのイメージ

WEBアプリからAWSへの通信時のエラーハンドリングについて、AWS SDK開発者ガイドを基に以下を検討した

  • 実現したい仕様

    • AWS SDK経由のリクエスト実行時にクレデンシャルエラーを検知したい
      • クレデンシャルの認証エラーであることをユーザにエラーメッセージで教えたい
        • Credentialの問題なのか、リクエストの問題(例えば指定したリソースが存在しない)なのか知りたい
        • ユーザは原因を判断できないと、次のアクションが分からない
    • クレデンシャルエラーを検知した場合に処理をストップ
      • クレデンシャルに誤りがある場合、AWSへの複数ののリクエストを実行しても全て失敗する
      • 一つエラーが出た時点で止めることでUXを向上させたい
  • AWS SDKとは

    • WEBアプリからAWSにリクエストする際に利用するもの
    • AWS Credential(accessKeyId, secretAccessKey)が必要
      • 今回は↑が間違っていた場合に検知したい
    • サービスオブジェクトメソッドは呼び出されると、AWS.Response オブジェクトをコールバック関数に渡すことで返す
    • AWS.Response オブジェクトのプロパティを通じて、レスポンスの内容にアクセス可能
  • AWS.Response オブジェクトのプロパティ x 2

    1. data プロパティ
    2. error プロパティ
      • ここの内容でエラーの種類を見分けられそう

        エラーメッセージの検証

  • Credentialの認証エラー時のメッセージを確認してみる

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // aws-sdkを変数AWSとしてimport
    import * as AWS from 'aws-sdk';

    region = XXXX;

    // AWS SDK各サービスのオブジェクトをまとめて宣言
    let ec2 = new AWS.EC2({region: region});

    // Ex. VPCの情報をリクエスト(describeVpcs)
    // AWSにリクエストを発信し、返り値(dataプロパティ & errorプロパティ)に応じた処理を実行
    ec2.describeVpcs({}, (err, data ) => {
    if (err) { // Error発生時の処理
    // 以下でエラーメッセージを見てみる
    alert(err); // AuthFailure: AWS was not able to validate the provided access credentials
    }
    else { // データを取得した際の処理
    resolve(data); // 問題無くresolveしたら()の値を返す
    }
    });

  • Credentialのエラーメッセージは以下が出た

    • alert(err)の結果
      1
      AuthFailure: AWS was not able to validate the provided access credentials

alertで確認したエラーメッセージ

その他

Angular8:”global is not defined”の回避策

概要

  • Angular8で以下のエラーにハマった際の解消法を解説します

    1
    ”global is not defined”
  • 上記のエラーについて

    • Angularでグローバルオブジェクトを参照する外部ライブラリを利用している環境で発生する事象
    • 今回はAngularとAWS間のAPI連携機能を実装した際に発生
  • 環境の詳細

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    Angular CLI: 8.3.24
    Node: 10.16.3
    OS: win32 x64
    Angular: 8.2.14
    ... animations, common, compiler, compiler-cli, core, forms
    ... language-service, platform-browser, platform-browser-dynamic
    ... router

    Package Version
    -----------------------------------------------------------
    @angular-devkit/architect 0.803.24
    @angular-devkit/build-angular 0.803.24
    @angular-devkit/build-optimizer 0.803.24
    @angular-devkit/build-webpack 0.803.24
    @angular-devkit/core 8.3.24
    @angular-devkit/schematics 8.3.24
    @angular/cdk 8.2.3
    @angular/cli 8.3.24
    @angular/material 8.2.3
    @ngtools/webpack 8.3.24
    @schematics/angular 8.3.24
    @schematics/update 0.803.24
    rxjs 6.4.0
    typescript 3.5.3
    webpack 4.39.2

解決策

  • pollyfills.tsに設定が必要
    • 所在
      • “pj-name”\srcの配下
    • 以下を追記すると解決します
      // "global is not defined"の対応
      (window as any).global = window;

解説

  • polyfillとは
    • JavaScriptのversion間の互換性を補うもの
    • 利用したい機能に未対応のブラウザでも使えるように、同等の機能をJavaScriptで供給できる
  • pollyfills.ts
    • Angularにおけるpolyfillの設定ファイル
    • 例えば、Angularで開発したAPをIEでも動かしたい時には設定が必要
      • Angularは”デフォルトではIEに未対応”です

Angular x AWS SDK for JavaScriptの始め方

  • Angularで開発していたアプリケーションにaws-sdkを導入する際の備忘録
    • AWS SDKを入れることで、アプリケーションからAWSのリソースを操作可能になります
      • ex.) S3やDynamoDBへのデータの格納、Cognitoによる認証、Lambdaの実行…
      • SDK: Software Development Kit
        • 特定のソフトウェアを開発する際に必要なツールのセット
  • Angularの場合、公式の開発者ガイド通りにやると鬼のようにエラーが出るので共有しておきます。ひと手間必要でした。

1. aws sdk for javascriptのinstall

  • angular PJ直下で実行
    1
    npm install aws-sdk --save-dev
  • この時点でAPを確認すると、以下のエラーが大量に出ます
    • APの画面もブラウザに表示されなくなります
1
2
3
>ng serve --open

ERROR in node_modules/aws-sdk/clients/acm.d.ts:141:37 - error TS2591: Cannot find name 'Buffer'. Do you need to install type definitions for node? Try `npm i @types/node` and then add `node` to the types field in your tsconfig.

2. @types/nodeをinstallする

  • Angular PJ直下で以下を実行
    1
    2
    3
    4
    5
    npm install --save @types/node

    + @types/node@8.9.5
    updated 1 package and audited 19123 packages in 41.418s
    found 0 vulnerabilities

3. tsconfig.json ファイルに以下を追記

  • Angular PJ直下にあります

    1
    2
    3
    "compilerOptions": {
    "types": ["node"]
    }
  • 場所は以下

    1
    > code .\tsconfig.json
    1. tsconfig.app.json にも、同じく追記
      • Angular PJ直下にあります
        1
        2
        3
        "compilerOptions": {
        "types": ["node"]
        }
  • エラーの解消を確認

    • ng serve時に正しくAPの画面が表示される
  • ここまででAngular APからAWSのリソースとAPI連携する下準備が整いました

    • 以下についても後日UP予定です
      • AWSの各リソースの利用方法、実装方法
      • Ampliyfy(BaaS)でAWSと連携させる手法

参考

関連記事

@EventEmitter @Input @Output @ViewChild ACM AMP API Gateway AR AR.js AR.js Studio AWS AWS Amplify AWS Budgets AWS Cost Explorer AWS SDK for JavaScript AddThis Adobe XD Alexa Amazon CloudWatch Amazon Honycode Amazon SNS Android Angular Angular Material AngularFire AppSync Augury C CDN CI/CD Cloud Craft Cloud9 CloudFormation CloudFront CloudTrail Cognito Cost Anomaly Detection Cubase ai Cubasis LE DTM Disqus DynamoDB Elgato HD 60S Firebase Firebase Hosting Former2 Github Github Actions Github.com GithubEnterprise GithubPages Google Chrome Google Cloud Shell GraphQL Hexo Hosting IAM Ionic JSON JavaScript LadioCast Logging LowCode MFA MS Authentication MacBook Pro 16 Mind Node NETDUETTO Netflix Party Netlify Network NoCode Observable PO PdM Promise RPA ReactiveForm Recognition Route53 S3 SAM(Serverless Application Model) SAR SSL SYNCROOM Schematics ScrumInc Serverless Service Siri Sitemap Spark AR Steinberg UR44C Teams Touch Cast Studio Treetable TypeScript UI UI Bakery WAF WAFv2 WEB Page Dev WEB会議 WebAR WebSocketAPI Webhook Windows Power Automate Wireshark aot async/await aws config cloud9 display.land draw.io e2e test filter() forkJoin() google search console hexo-generator-amp iOS iPad Pro iPhone icarus map() mat input mat tree mat-checkbox mat-input mat-selection-list mmhmm ngFor plantUML popIn Aladdin2 then() vscode ”global is not defined” らくがきAR アジャイル アジャイル開発 クロスプラットフォーム ショートカット スクラム スクラム開発 テレワーク ファイル操作 ブラウザ型IDE プロダクトオーナー プロダクトマネージャー プロトタイピング リモートセッション 共同開発 双方向データバインディング 待ち合わせ処理 認定スクラムマスター 静的WEB Hosting 静的WEBサイトHosting
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×