目的
- Cloud9上での aws amplify, aws appsync を利用する開発環境の構築
- React上での subscription による リアルタイムデータ配信アプリの構築
- amplify の機能による S3+CloudFlont でのアプリのデプロイ
Vue.js バージョンはこちら
前提
- 利用するリージョンは ap-northeast-1
- CodeCommitのリポジトリ名は amplify_test_react
- amplifyで利用するiamユーザは amplify-test-user
- アプリ名はmytodo
- api名はmytodoapi
注意
この投稿は @aws_amplify/api, @aws_amplify/pubsub パッケージを利用しています。
2019年12月では、aws_amplify, aws_amplify_react パッケージと同時に利用することはできません。
AWSKinesisFirehoseProvider.js あたりでエラーが発生する場合はパッケージの混同を疑ってみてください。
構築手順
- CodeCommitへのGitリポジトリ作成 * 'amplify_test_react'を使用
- Cloud9の開発環境作成 * aws consoleで作成
- Cloud9の一時認証の利用を解除
- ツールバーのAWS Cloud9でメニューを開く
- Preferencesを開く
- AWS SETTINGSを開く
- Credentialsを開く
- AWS managed temporary credentials をオフにする
- 開発環境とGitリポジトリの連携
$ git clone ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/amplify_test_react
- nodeのインストール
最新、または、好みのバージョンを確認
$ nvm ls-remote
指定したバージョンでインストールを実行
$ nvm install 指定のバージョン
- aws amplify cli のインストール
$ npm install -g @aws-amplify/cli
- amplify の初期設定
- configureを実行
$ amplify configure
- 管理者アカウントでaws consoleをブラウザで開く
Follow these steps to set up access to your AWS account: Sign in to your AWS administrator account: https://console.aws.amazon.com/ Press Enter to continue
- 利用するリージョンを選択、ユーザ名を入力
出力されたurlをaws cosoleを開けたブラウザで開いてユーザを作成
デフォルトの値は入っているので作成を完了するだけ
Specify the AWS Region ? region: ap-northeast-1 Specify the username of the new IAM user: ? user name: amplify-test-user Complete the user creation using the AWS console https://console.aws.amazon.com/iam/home?region=undefined#/users$new?step=final&accessKey&userNames=amplify-test-user&permissionType=policies&policies=arn:aws:iam::aws:policy%2FAdministratorAccess Press Enter to continue
- ユーザ作成で得ることのできた accessKeyId と secretAccessKey を入力
Enter the access key of the newly created user: ? accessKeyId: ******************** ? secretAccessKey: **************************************** This would update/create the AWS Profile in your local machine ? Profile Name: default Successfully set up the new user.
- configureを実行
- react のインストールとプロジェクトの作成
$ npx create-react-app mytodo $ cd mytodo
- アプリケーションを実行して確認
$ npm start
メニューの Preview -> Preview Running Application を実行
Cloud9内のブラウザでReactのセットアップが完了していることを確認 - SecurityErrorが表示される場合
以下のエラーが表示される場合は、React Scriptの問題
SecurityError: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.
対応するには React Script 3.3.0 を利用しないようにする
以下の通り React Script 3.2.0 を利用するにうにpackage.jsonを修正してインストールするpackage.json- "react-scripts": "3.3.0" + "react-scripts": "3.2.0"
- aws-amplify をインストール
$ npm install @aws-amplify/api $ npm install @aws-amplify/pubsub $ npm install aws-amplify-react
- amplify の初期設定
$ amplify init Note: It is recommended to run this command from the root of your app directory ? Enter a name for the project mytodo ? Enter a name for the environment dev ? Choose your default editor: Vim (via Terminal, Mac OS only) ? Choose the type of app that you're building javascript Please tell us about your project ? What javascript framework are you using react ? Source Directory Path: src ? Distribution Directory Path: build ? Build Command: npm run-script build ? Start Command: npm run-script start
- amplify の初期設定確認
$ amplify status Current Environment: dev | Category | Resource name | Operation | Provider plugin | | -------- | ------------- | --------- | --------------- |
- api の追加準備
$ amplify add api ? Please select from one of the below mentioned services: GraphQL ? Provide API name: mytodoapi ? Choose the default authorization type for the API API key ? Enter a description for the API key: ? After how many days from now the API key should expire (1-365): 365 ? Do you want to configure advanced settings for the GraphQL API No, I am done. ? Do you have an annotated GraphQL schema? No ? Do you want a guided schema creation? Yes ? What best describes your project: Single object with fields (e.g., “Todo” with ID, name, description) ? Do you want to edit the schema now? No
- api の追加内容確認
$ amplify status Current Environment: dev | Category | Resource name | Operation | Provider plugin | | -------- | ------------- | --------- | ----------------- | | Api | mytodoapi | Create | awscloudformation |
- バックエンドに api の追加内容を反映
$ amplify push Current Environment: dev | Category | Resource name | Operation | Provider plugin | | -------- | ------------- | --------- | ----------------- | | Api | mytodoapi | Create | awscloudformation | ? Are you sure you want to continue? Yes ? Do you want to generate code for your newly created GraphQL API Yes ? Choose the code generation language target javascript ? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.js ? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions Yes ? Enter maximum statement depth [increase from default if your schema is deeply nested] 2
- mytodo を修正
- App.js を修正
App.js
import React, { useEffect, useReducer } from 'react'; import API, { graphqlOperation } from '@aws-amplify/api'; import PubSub from '@aws-amplify/pubsub'; import { createTodo } from './graphql/mutations'; import { listTodos } from './graphql/queries'; import awsconfig from './aws-exports'; import './App.css'; // Configure Amplify API.configure(awsconfig); PubSub.configure(awsconfig); // Action Types const QUERY = 'QUERY'; const initialState = { todos: [], }; const reducer = (state, action) => { switch (action.type) { case QUERY: return {...state, todos: action.todos}; default: return state; } }; async function createNewTodo() { const todo = { name: "New Todo Title", description: "do something at " + Date() } await API.graphql(graphqlOperation(createTodo, { input: todo })); } function App() { const [state, dispatch] = useReducer(reducer, initialState); useEffect(() => { async function getData() { const todoData = await API.graphql(graphqlOperation(listTodos)); dispatch({ type: QUERY, todos: todoData.data.listTodos.items }); } getData(); }, []); return ( <div> <div className="App"> <button onClick={createNewTodo}>Add Todo</button> </div> <div> {state.todos.length > 0 ? state.todos.map((todo) => <p key={todo.id}>{todo.name} : {todo.description}</p>) : <p>Add Todo</p> } </div> </div> ); } export default App;
- 実行してブラウザでTodoが追加されることを確認
Add Todoボタンをクリックしたあと、リロードすることでTodoが追加されていることが確認できる
- App.js を修正
- subscription を利用してみる
- App.js を修正
App.js
import React, { useEffect, useReducer } from 'react'; import API, { graphqlOperation } from '@aws-amplify/api'; import PubSub from '@aws-amplify/pubsub'; import { createTodo } from './graphql/mutations'; import { listTodos } from './graphql/queries'; import { onCreateTodo } from './graphql/subscriptions'; import awsconfig from './aws-exports'; import './App.css'; // Configure Amplify API.configure(awsconfig); PubSub.configure(awsconfig); // Action Types const QUERY = 'QUERY'; const SUBSCRIPTION = 'SUBSCRIPTION'; const initialState = { todos: [], }; const reducer = (state, action) => { switch (action.type) { case QUERY: return {...state, todos: action.todos}; case SUBSCRIPTION: return {...state, todos:[...state.todos, action.todo]}; default: return state; } }; async function createNewTodo() { const todo = { name: "New Todo Title", description: "do something at " + Date() } await API.graphql(graphqlOperation(createTodo, { input: todo })); } function App() { const [state, dispatch] = useReducer(reducer, initialState); useEffect(() => { async function getData() { const todoData = await API.graphql(graphqlOperation(listTodos)); dispatch({ type: QUERY, todos: todoData.data.listTodos.items }); } getData(); const subscription = API.graphql(graphqlOperation(onCreateTodo)).subscribe({ next: (eventData) => { const todo = eventData.value.data.onCreateTodo; dispatch({ type: SUBSCRIPTION, todo }); } }); return () => subscription.unsubscribe(); }, []); return ( <div> <div className="App"> <button onClick={createNewTodo}>Add Todo</button> </div> <div> {state.todos.length > 0 ? state.todos.map((todo) => <p key={todo.id}>{todo.name} : {todo.description}</p>) : <p>Add Todo</p> } </div> </div> ); } export default App;
- 実行して2つのブラウザで同期的にTodoが追加されることを確認
- App.js を修正
- Hosting の準備
$ amplify add hosting ? Select the environment setup: DEV (S3 only with HTTP) ? hosting bucket name mytodo-20191223025707-hostingbucket ? index doc for the website index.html ? error doc for the website index.html
- Hosting の追加内容の確認
$ amplify status Current Environment: dev | Category | Resource name | Operation | Provider plugin | | -------- | --------------- | --------- | ----------------- | | Hosting | S3AndCloudFront | Create | awscloudformation | | Api | mytodoapi | No Change | awscloudformation |
- バックエンドに Hosting の追加内容を反映
$ amplify push Current Environment: dev | Category | Resource name | Operation | Provider plugin | | -------- | --------------- | --------- | ----------------- | | Hosting | S3AndCloudFront | Create | awscloudformation | | Api | mytodoapi | No Change | awscloudformation | ? Are you sure you want to continue? Yes
- バックエンドの Hosting を公開
$ amplify publish
- PublishされたURLを2つのブラウザで開いて同期的にTodoが追加されることを確認
- 作成した amplify のリソースを削除
$ amplify delete
amplify delete した後、再度 amplify init で作成し直す場合は、aws-exports.js ファイルを削除しておく。init や add で更新されない。
amplify init したアプリを deleteせずに再度initする場合、CloudFormation上から削除できなくなるので、注意。