Amazon Web Services ブログ
AWS CDKまたはCloudFormationを使用し、カスタムAWSリソースでAmplifyバックエンドを拡張する新機能「カスタム」のご紹介
この記事は、Extend Amplify backend with custom AWS resources using AWS CDK or CloudFormation を翻訳したものです。
AWS AmplifyでAWS Cloud Development Kit(CDK)またはAWS CloudFormationを使用し、Amplifyが作成したバックエンドに175以上のAWSサービスを追加する新しいコマンドamplify add custom
が発表されました。カスタムリソースを追加する新しい機能により、開発者は1つのコマンドでAmplifyに組み込み済みのユースケース以外にリソースを追加できます。
AWS Amplifyは、AWS上でモバイルアプリやウェブアプリを構築するための最も速くて簡単な手段を提供するサービスです。 Amplifyは、フロントエンドのウェブ開発者とモバイル開発者がAWSサービスの力を活用して、革新的で機能豊富なアプリケーションを構築できるようにする一連のツールとサービスで構成されています。 AWS Amplify CLIは、フロントエンド開発者がクラウドでアプリバックエンドを簡単に作成できるコマンドラインツールチェーンです。
この記事で学習する内容
- カスタムAWSリソースをAmplifyプロジェクトに追加する方法
- カスタムAWSリソースをAmplifyのマルチ環境ワークフローと互換性のあるものにする方法
- Lambda関数からカスタムAWSリソースにアクセスする方法
この記事を通して構築するもの:
- 友人と共有して全ての材料を追加できるディナーパーティーのショッピングリストアプリ
- ショッピングの準備に役立つように、Amazon SNSを使用して必要な全ての材料を含む要約メールを受信する機能
前提条件:
- 最新のAmplify CLIをインストールされていること。バージョン7以降が必要です。
- インストールする場合はターミナルを開き、
npm i -g @aws-amplify/cli
を実行します。
- インストールする場合はターミナルを開き、
- Amplify CLIがすでに設定されていること。
- Amplify CLIがまだ設定されていない場合は、ドキュメントページのこちらのガイドにしたがって設定してください。
1. ReactとAmplifyプロジェクトを初期化する
まず、新しいディレクトリを作成し、Amplifyプロジェクトを初期化します。
npx create-react-app amplified-shopping
cd amplified-shopping
amplify init -y
Amplifyプロジェクトは、アプリのバックエンドを開発するための出発点です。 Amplifyプロジェクトが初期化された後、amplify add api
を介して、Amazon DynamoDBによってサポートされるGraphQL APIなどのバックエンドリソースを簡単に追加できます。
2. ショッピングリストアイテムを保存するようにアプリデータモデルを構成する
次に、ショッピングリストのデータをどこかに保存する必要があります。 Amplify CLIは、GraphQL APIとその基礎となるリソースの作成に役立つ「APIカテゴリー」を提供します。amplify add api
を実行して、GraphQL APIを作成します。
amplify add api
(このデモは全てデフォルトの設定で進めることができます。)
CLIを実行すると、GraphQLスキーマを編集するように要求されます。GraphQLスキーマはデータモデルを定義するため、Amplifyが生成する基盤となるインフラストラクチャも定義します。
アプリのschema.graphqlファイルには以下のデータモデルを使用します。
type ShoppingItem @model { #Creates a database for ShoppingItem
id: ID!
ingredient: String
quantity: Float
unit: String
}
type Mutation {
sendSummaryEmail: Boolean @function(name: "sendSummary-${env}")
}
@modelディレクティブを使用してtypeを指定すると、そのtypeのフィールドをサポートするDynamoDBテーブルが作成されます。上記の場合ShoppingItemテーブルは、ID、ingredient、quantity、unitで作成されます。 @functionディレクティブを使用すると、GraphQL APIリクエストを処理するLambda関数に再ルーティングできます。後でこのLambda関数を使用して、メッセージをAmazon SNSにpublishし、メール通知をトリガーします。
3. AmazonSNSトピックをカスタムAWSリソースとしてAmplifyプロジェクトに追加する
ここまでの手順でバックエンドのデータベースがセットアップされました。Amazon SNSトピックを作成してメールサブスクリプションを利用しましょう。Amazon SNSトピックはメッセージを受信するたびに、事前に指定されたメールアドレスにメッセージを転送します。
現在、Amazon SNSトピックの追加はAmplifyに組み込まれていませんが、以下の手順を実行してカスタムAWSリソースを追加できるようになりました。
amplify add custom
このアプリでは、AWS CDKを使用してカスタムAWSリソースを定義します。ただし、これはCloudFormationでも簡単に定義できます。 Amplify CLIは、すべてのカスタムリソース定義を含む新しいcdk-stack.tsファイルを開きます。
cdk-stack.tsファイルを編集し、Amazon SNSトピックとメールサブスクリプションを作成しましょう。
(注:以下のコードスニペットの”<YOUR_EMAIL_ADDRESS_HERE>”を必ず置き換えてください)
import * as cdk from '@aws-cdk/core';
import * as AmplifyHelpers from '@aws-amplify/cli-extensibility-helper';
import * as sns from '@aws-cdk/aws-sns';
import * as subs from '@aws-cdk/aws-sns-subscriptions';
export class cdkStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps, amplifyResourceProps?: AmplifyHelpers.AmplifyResourceProps) {
super(scope, id, props);
/* Do not remove - Amplify CLI automatically injects the current deployment environment in this input parameter */
new cdk.CfnParameter(this, 'env', {
type: 'String',
description: 'Current Amplify CLI env name',
});
// Create the SNS topic
const topic = new sns.Topic(this, 'sns-topic', {
// Reference the Amplify env to ensure multi-env workflow function correctly
topicName: `sns-topic-${AmplifyHelpers.getProjectInfo().projectName}-${cdk.Fn.ref('env')}`
});
// Add an email subscription
topic.addSubscription(new subs.EmailSubscription("<YOUR_EMAIL_ADDRESS_HERE>"));
}
}
この時点で、次のコマンドを実行してアプリのバックエンドのデプロイを試みることができます。
amplify push -y
新しいメールサブスクリプションが設定されると、後続のメッセージを受信するためにメール受信者は「Confirm subscription」をする必要があります。メールを確認して「Confirm subscription」をクリックしてください。
4.すべてを接続するLambda関数を構成する
ここまで、メール通知のセットアップとデータベースの構成が完了しました。あとは全てを繋ぎ合わせるようにLambda関数を設定するだけです。
amplify add function
GraphQL APIのミューテーションにアクセスできるNode.js関数を作成するには、以下の選択肢を必ず選択してください。
※GraphQLスキーマで指定されている関数名「sendSummary」を使用してください。
? Select which capability you want to add:
> Lambda function (serverless function)
? Provide an AWS Lambda function name:
> sendSummary
? Choose the runtime that you want to use:
> NodeJS
? Choose the function template that you want to use:
> Hello World
? Do you want to configure advanced settings?
> Yes
? Do you want to access other resources in this project from your Lambda function?
> Yes
? Select the categories you want this function to have access to.
> api
? Select the operations you want to permit on amplifiedshopping
> Mutation
(以降の選択肢は全てデフォルトのものを選択して進めてください)
CLIフローの最後で関数コードを編集できるようになります。Lambda関数のロジックを編集する前に、ディレクトリに移動してnode-fetch
のパッケージを追加し、GraphQL APIを簡単に呼び出せるようにします。
cd amplify/backend/function/sendSummary/src
npm install node-fetch@2
以下のコードスニペットを追加します。
- 全てのショッピングアイテムを取得する
- メールのメッセージをフォーマットする
- Amazon SNS経由でメール通知を送信する
/* Amplify Params - DO NOT EDIT
API_AMPLIFIEDSHOPPING_GRAPHQLAPIENDPOINTOUTPUT
API_AMPLIFIEDSHOPPING_GRAPHQLAPIIDOUTPUT
API_AMPLIFIEDSHOPPING_GRAPHQLAPIKEYOUTPUT
ENV
REGION
Amplify Params - DO NOT EDIT */
const fetch = require("node-fetch")
const AWS = require('aws-sdk')
const sns = new AWS.SNS()
const graphqlQuery = `query listShoppingItems {
listShoppingItems {
items {
id
ingredient
quantity
unit
}
}
}
`
exports.handler = async (event) => {
const response = await fetch(process.env.API_AMPLIFIEDSHOPPING_GRAPHQLAPIENDPOINTOUTPUT, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.API_AMPLIFIEDSHOPPING_GRAPHQLAPIKEYOUTPUT
},
body: JSON.stringify({
query: graphqlQuery,
operationName: "listShoppingItems",
})
})
const result = await response.json()
const shoppingItems = result.data.listShoppingItems.items
await sns.publish({
// For demo purposes hard-coded, normally recommended to use environment variable
TopicArn: "<YOUR-SNS-TOPIC-ARN-HERE>",
Message: `Here's shopping cart summary - ${new Date().toDateString()}:\n` +
`${shoppingItems.map(item => `${item.quantity} ${item.unit} - ${item.ingredient}`)
.join('\n')}`
}).promise().catch(e => console.log(e))
return true
};
“<YOUR-SNS-TOPIC-ARN-HERE>”をAmazon SNSトピックARNに上書きしたことを確認してください。Amazon SNSトピックARNはサブスクリプション確認メールのすぐ下の「You have chosen to subscribe to the topic:」に、以下のように記述されています。
arn:aws:sns:<your-region>:<your-aws-account-id>:sns-topic-amplifiedshopping-dev
次にLambda関数がこのAmazon SNSトピックのPublishアクションにアクセスできるように、カスタムIAMポリシーを追加する必要があります。Lambda関数フォルダーamplify/backend/function/sendSummary/
にはcustom-policies.jsonがあります。このファイルに追加するカスタムIAMポリシーはここで定義できます。Amazon SNSトピックにメッセージを公開するためのアクセスを提供するには、custom-policies.jsonファイルを次のように置き換えます。
[
{
"Action": ["sns:Publish"],
"Resource": ["arn:aws:sns:*:*:sns-topic-amplifiedshopping-${env}"]
}
]
全ての設定が完了したので、バックエンドをAWS上にデプロイします。
amplify push -y
5.フロントエンドを構築する
まず、プロジェクトに必要な全てのパッケージをインストールする必要があります。
Reactアプリのルートディレクトリに移動して、次のコマンドを実行します。
npm install aws-amplify recipe-ingredient-parser-v3
これにより、Amplifyライブラリがインストールされ、アプリがAWS上のバックエンドに接続できるようになります。さらに、自由形式のテキストから構造化された構成要素のデータを抽出するために、オープンソースの言語パーサーライブラリを使用します。例えばsix cups of milk
を{ingredient: "milk", quantity: 6, unit: "cup"}
に変換します。
それでは、ReactアプリでAmplifyを設定して、AWS上のバックエンドに接続できるように設定します。index.jsファイルに移動し、ReactDOM.render(...)
の直前に次の3行のコードを追加します。
import Amplify from 'aws-amplify'
import awsconfig from './aws-exports'
Amplify.configure(awsconfig)
次にApp.jsを以下の内容に置き換えます。
import { useEffect, useState } from 'react';
import { API } from 'aws-amplify';
import * as queries from './graphql/queries';
import * as mutations from './graphql/mutations';
import { parse } from 'recipe-ingredient-parser-v3';
function App() {
const [ingredient, setIngredient] = useState()
const [shoppingItems, setShoppingItems] = useState([])
const fetchShoppingList = async () => {
const response = await API.graphql({ query: queries.listShoppingItems })
setShoppingItems(response.data.listShoppingItems.items)
}
useEffect(() => {
fetchShoppingList()
}, [])
return (
<div className="App">
<input value={ingredient} onChange={e => setIngredient(e.target.value)}/>
<button onClick={async () => {
const parsed = parse(ingredient, 'eng')
console.log(parsed)
if (parsed.unit && parsed.ingredient && parsed.quantity) {
setIngredient("")
await API.graphql({
query: mutations.createShoppingItem,
variables: {
input: {
ingredient: parsed.ingredient,
quantity: parsed.quantity,
unit: parsed.unit
}
}
})
fetchShoppingList()
}
}}>Add ingredient</button>
<h1>Ingredients</h1>
<button onClick={fetchShoppingList}>Refresh</button>
<button onClick={async () => {
await API.graphql({
query: mutations.sendSummaryEmail
})
}}>Send summary email</button>
<ul>
{shoppingItems.map(({ ingredient, quantity, unit }) => <li>
<div>{quantity} {unit} - {ingredient}</div>
</li>)}
</ul>
</div>
);
}
export default App;
次に以下のコマンドを実行してアプリをテストします。
yarn start
ディナーパーティーのための材料をいくつか追加してみてください!次に「send summary email」をクリックして、受信トレイを確認してください。
🥳完成!
このブログ記事では、AWS AmplifyのAPIと関数の機能カテゴリを使用してフルスタックアプリを構築する方法を学習しました。また、未だAmplifyに組み込まれていないカスタムAWSリソースを追加する方法も学習しました。
このアプリを本番環境へ持っていくには何が必要でしょうか?まず最も重要なこととして、GraphQLスキーマの認証ルールを設定する必要があります。さらに、IAMを使用してGraphQL APIに対してLambda関数を認証する必要もあります。最後になりますが、メール受信者を追加する仕組みも導入する必要があります。
詳細については、以下のドキュメントを確認してください。
フィードバックがあればGitHubに共有するか、Discordのコミュニティに参加してください!
翻訳はGaming Solutions ArchitectのShintaro Watanabeが担当し、Developer Relations Engineer(Mobile/Web)のDaijiro WachiとPrototyping EngineerのTomohiro Tsukuiが監訳しました。