はじめに
Micorsoft の製品の一つ、Power Platform。
中でもPower AppsやPower Automateは、ノーコーディング(またはローコーディング)でかなり本格的なアプリが簡単に作れる、画期的な製品です。
また簡単なアプリならコーディングなしでサクッと作れてしまうので、ITエンジニアにも便利だと思います。
そこでお試しに、(趣味と実用を兼ねて)「カメラで撮影した画像を、AWSのS3バケットに保存する」アプリを作成しました。
なおPower Platformについては、「Power BI 王子」こと清水優吾さんが、素晴らしい資料を公開してますので、ご参照ください。
www.slideshare.net
使うもの
- Power Apps
- 上で説明した通りです。
- カスタムコネクタ
- AWS Lambda & AWS S3
- S3にファイルを保存する関係で使います。
- Serverless Framework
- もちろん今回も使います。
【注意】カスタムコネクタについて
カスタムコネクタですが、Power Appsで使用する場合「Premium限定機能」となります。(ダイアモンドのアイコンが表示されている)
そのため、試用は可能ですが、一定期間が過ぎると使用不可能(またはサブスクリプションの購入が必要)なので、注意してください。
※あくまで「Power Platformの色々な機能のお試し」として読んでください。
Power Apps側の作成
Power Apps側の機能ですが、こんな感じになってます。(「Kintai-Upload」は、なんとなく付けただけで、意味はないです)
- 「撮影」画面で、カメラ機能を使って撮影する。(撮影すると自動で「確認」画面に遷移する)
- 「確認」画面で「送信する」をクリックすると、S3バケットに撮影した画像をアップロードする。
- 「やりなおす」をクリックすると、「確認」画面に戻る
で、上記機能の実装方法なんですが、変に説明をするより、マイクロソフトの吉田大貴さんのこの動画を見た方が早いですので、そちらを参照ください。
マジでこの動画を参考にすれば、画像をS3にアップロードする直前までできてしまいます。
注意点としては、以下の通りです。
- 画面の移動は「Navigate()」関数を使う。
- JSON()関数を使うと、バイナリデータをBase64形式の文字列に変換できる。(詳細は下記)
- API Gatewayの設計上、今回はbase64形式の文字列に変換して送信します。
- 【参考】Power Appsにおける画像の扱いについて
# JSON([画像のバイナリデータ], JSONFormat.IncludeBinaryData) とすると、バイナリデータをBase64形式の文字列に変換できる。 # [画像のバイナリデータ]には「Image1.Image」など、「画像の表示部品の名前.Image」を指定する。 JSON(Image1.Image, JSONFormat.IncludeBinaryData)
AWS側の設定について
今回、カスタムコネクタ作成にはOpen API(swagger)の定義を利用します。
またOpen API定義はAPI Gatewayからエクスポートできるので、先にAWS側のリソースを作成する必要があります。
というわけで、今回もServerless Frameworkの出番です。
...といっても、Serverless Frameworkは過去記事でもかなり扱ってるので、今回はserverless.ymlの内容だけ。
service: kintai-upload provider: name: aws runtime: nodejs12.x stage: dev region: ap-northeast-1 stackName: ${self:service} apiName: api-${self:service} profile: default iamRoleStatements: - Effect: "Allow" Action: - "s3:ListBucket" - "s3:PutObject" - "s3:GetObject" Resource: - arn:aws:s3:::${self:service}/* environment: TZ: Asia/Tokyo functions: CreateImage: handler: createImage.index events: - http: path: /create method: post request: parameters: body: imagebinary: false environment: BUCKET_NAME: ${self:service} SendSms: handler: sendSms.index events: - s3: bucket: ${self:service} event: s3:ObjectCreated:* environment: BUCKET_NAME: ${self:service}
ざっくりまとめると、下記の流れです。(「SendSms」Lambda自体は、今回の記事では未使用)
- api-kintai-uploadという名前のAPI Gatewayを作って、
- そこに「CraeteImage」Lambdaを実行するエンドポイントを作成して、
- 「kintai-upload」という名前のバケットを作成して、そこに「createObject」トリガを定義して
- 上記トリガで「SendSms」Lambdaを実行する
なお「resourceセクションへのS3バケットの定義(てか、そもそもresourceセクション自体)がないけど」と思ったかもしれませんが、「function」セクションの「events」で「s3」を定義するだけで、下記設定を自動で行ってくれますので、「resources」セクションの定義は不要です。
カスタムコントロールの作成
で、肝心のカスタムコネクタの作成ですが、これはPower Appのホーム画面から[データ]-[カスタムコネクタ]を選択し、右上の「カスタムコネクタの新規作成」をクリックすればOKです。
なお、作成方法がいくつかありますが、今回は「OpenAPIファイルをインポート」で実行します。
OpenAPIファイルの取得
OpenAPIファイルですが、API Gatewayの場合、該当のAPIを選択した後、下記手順で取得できます。
- 左のリストから「ステージ」を選択
- 「ステージ」で該当ステージを選択後、「エクスポート」タブを選択
- 「次の形式を選択」で「Swagger」を選択後、ファイル形式に「JSON」を選択する。
- OpenAPI3、及びYAML形式はまだサポートしてません。
ファイルをDLしたら、「カスタムコネクタの作成」の「OpenAPIファイルをインポートします」で、DLしたファイルを選択します。
また「コネクタ名」に、一意の名前を入力します。
で、あとは「全般」「セキュリティ」「定義」などを設定しますが、ここからは「swaggerエディタ」をONにすれば直接OpenAPIファイルの内容を編集できますので、そちらで編集します。
今回は。こんな感じで定義しました。
swagger: '2.0' info: {version: '2020-02-29T10:45:32Z', title: api-kintai-upload-to-cloud} host: *******.amazonaws.com basePath: /dev schemes: [] consumes: [] produces: [] paths: /create: post: responses: '200': {description: OK} '400': {description: Request Error} '500': {description: Internal Error} default: {description: Something Error} parameters: - name: imagebinary in: body description: kintai file binary required: true schema: {type: string} operationId: Kintai-upload-to-cloud-makky12 description: Kintai-upload-to-cloud用のカスタムコネクタ summary: Kintai-upload-to-cloud用のカスタムコネクタ definitions: {} responses: {} securityDefinitions: {} security: [] tags: []
ちなみに、テストをする場合「テスト」タブで必要な値を入力すればOKです。
(今回の場合、「imagebinary」にbase64文字列に変換した画像のバイナリデータを入力する)
Power Appsに組み込む
で、作成したカスタムコネクタをPower Appsに組み込む方法ですが、これは左のツリーの[データソース]-[コネクタ]から、先程作成したカスタムコネクタを選択すればOKです。
そして、実際にAPIにリクエストを送るには、ボタンの「onSelect」イベントなどで、下記のように設定すればOKです。
# 「api-kintai-upload-to-cloud」は、カスタムコネクタ名。 # 「Kintaiuploadtocloudmakky12」は、OpenAPIの「operationId」の値。(「定義」タブの「操作ID」で設定可能) # imageBase64は、base64文字列に変換した画像のバイナリデータ 'api-kintai-upload-to-cloud'.Kintaiuploadtocloudmakky12(imageBase64);
S3バケットに保存する。
ここまでこれば、あとはLambda側の処理です。
Lambda側では、特に特別なことはしていません。
よく見かける、画像をs3バケットに保存する処理だと思います。
強いて言えば、注意するのは下記2点です。
- JSON()関数でbase64文字列にした場合、先頭と末尾に「"」がついているので、「"」を除去する
- その他、「data:image/png;base64,」という文字列も付与されるので、これを取り除く
// @ts-check 'use strict'; const AWS = require("aws-sdk"); const S3 = new AWS.S3(); const moment = require("moment"); module.exports.index = async event => { let statusCode = 200; let message = ""; try { console.info(`[even] ${JSON.stringify(event)})`); console.info(`[event body] ${event.body})`); const bodyReplaced = event.body.replace(/\"/g, "").replace("data:image/png;base64,", ""); console.info(`[event replaced] ${bodyReplaced})`) const timeStamp = moment().format("YYYYMMDDHHmmssSSS"); const params = { Bucket: process.env.BUCKET_NAME, Body: Buffer.from(bodyReplaced, 'base64'), Key: `kintai_${timeStamp}.png`, ContentType: "image/png" }; const data = await S3.putObject(params).promise(); // console.info(`[S3 data] ${JSON.stringify(data)}`); } catch (error) { statusCode = 500; message = error.message; console.error(`[error Message] ${message}`); } return { statusCode: statusCode, body: JSON.stringify({ message: message }), }; };
結果
「送信する」ボタンをクリックすると、S3バケットに画像ファイル(*.png)が保存されます。
そして、ダウンロードして画像ビューワーで見ると、問題なく表示できます。
まとめ
以上、カスタムコネクタを使用して、画像をS3バケットにアップロードする方法でした。
カスタムコネクタはプレミアム限定機能ですが、こういう感じで、自作APIなどの操作をローコーディングで行えます。
また、自作APIでなくても、プレミアム限定でなくても使用できるAPIもありますので(Twitterとか)、非常に便利です。
Power AppsやPower Automateなど、Power Platform製品、なかなか便利なので、今後も使っていきたいです。
それではまた。