Cognito にユーザーがプールされたら、DynamoDBのUserテーブルにユーザー情報が追加され、AppSyncでクエリできるようにするには
要件は
- ユーザー閲覧機歴機能 (No.1) ユーザーとMovieのデータベースを紐づける
- ユーザー閲覧機歴機能 (No.2) ユーザーが閲覧したら、該当のサイドナビゲーションにチェックが付く
- ユーザー閲覧機歴機能 (No.3) ユーザーが閲覧したら、プロフィールに閲覧記録が書かれる
まずは、「1」の作成に必要な、全体工程は以下。
■「1. ユーザー閲覧機歴機能 (No.1) ユーザーとMovieのデータベースを紐づける工程の全体感
- Bitbucketへ、新たな空のリポジトリ「applat_release03」を作り、作業ディレクトリにクローンする。
Cognito -Lambda - DynamoDB - AppSync のトリガーフローが通った、新しい開発(公開)環境「applat-release03」を、新しいプロファイル「dev00003」で構築する。3. の環境に新しいnextプロジェクトと共に構築。
イベントは2つ。認証後とログイン後。
現在の開発環境「applat-release02」のデータベースのエクスポート先を、S3のパケットに作る。
- の「Movie」「Caption」(各言語分)のテーブルを全てエクスポート。
- で作成したパケットから、3. で新たに作った環境のDynamoDBへ、各言語のMovieとCaptionのデータをインポートする。
- で作った新しいローカル環境へ、「applat-release02」のフロントエンド部分を移行する。バックエンドに関わるsrcフォルダやAmplifyフォルダは絶対移動させないこと。
- で作った新しいリポジトリにpushする
- 全体をamplify push、そしてamplify publishする。
ここまでで、要件1 が完了する。
ここからは、
- -
Cognito -Lambda - DynamoDB - AppSync のトリガーフローが通った、新しい開発(公開)環境「applat-release03」を、新しいプロファイル「dev00003」で構築する。3. の環境に新しいnextプロジェクトと共に構築。
イベントは2つ。認証後とログイン後。
- -
について、記録していく。
■「2」Cognito -Lambda - DynamoDB - AppSync のトリガーフローについて
1. Amplify プロファイル設定
Amplify を使ったプロジェクト用のI AMユーザを、以下のコマンドで生成する。
amplify configure
そして、プロファイル名を設定。
2. Next.jsのインストール
next.jsフレームワークの新規作成
npx create-next-app .
3. 初期化
プロジェクトの初期化
amplify init
4. 最低限必要な依存関係のインストール
yarn add @aws-amplify/ui-react aws-amplify
4. AppSyncとUserテーブルほか必要なテーブルの作成
amplify add api
スキーマのコードは以下。
ここでauthを仕込んでおけば、次のamplify pushでauthのフローが始まる。
type User @model @auth( rules: [ {allow: groups, groups: ["Admin"]}, {allow: owner, ownerField: "username", operations: [read]} ] ){ id: ID! username: String email: String moviecheck: MovieCheck @hasOne } type MovieCheck @model { id: ID! user: User @belongsTo checkuser: String checklist:[CheckList] @hasMany } type CheckList @model { id: Int! lang: String! module: String! part: String! page: String! check: Boolean moviecheck: MovieCheck @belongsTo } type MovieEn @model { id: ID! lang: String! module: String! part: String! page: String! url: String! pagetitle: String! playalltime: String! captions: [CaptionEn] @hasMany outurl: String outurltitle: String movieEnPlaymovieId: String! } type MovieInd @model { id: ID! lang: String! module: String! part: String! page: String! url: String! pagetitle: String! playalltime: String! captions: [CaptionInd] @hasMany outurl: String outurltitle: String movieIndPlaymovieId: String! } type MovieVn @model { id: ID! lang: String! module: String! part: String! page: String! url: String! pagetitle: String! playalltime: String! captions: [CaptionVn] @hasMany outurl: String outurltitle: String movieVnPlaymovieId: String! } type MovieTha @model { id: ID! lang: String! module: String! part: String! page: String! url: String! pagetitle: String! playalltime: String! captions: [CaptionTha] @hasMany outurl: String outurltitle: String movieThaPlaymovieId: String! } type MovieTgl @model { id: ID! lang: String! module: String! part: String! page: String! url: String! pagetitle: String! playalltime: String! captions: [CaptionTgl] @hasMany outurl: String outurltitle: String movieTglPlaymovieId: String! } type MovieRus @model { id: ID! lang: String! module: String! part: String! page: String! url: String! pagetitle: String! playalltime: String! captions: [CaptionRus] @hasMany outurl: String outurltitle: String movieRusPlaymovieId: String! } type MovieNep @model { id: ID! lang: String! module: String! part: String! page: String! url: String! pagetitle: String! playalltime: String! captions: [CaptionNep] @hasMany outurl: String outurltitle: String movieNepPlaymovieId: String! } type MovieKhm @model { id: ID! lang: String! module: String! part: String! page: String! url: String! pagetitle: String! playalltime: String! captions: [CaptionKhm] @hasMany outurl: String outurltitle: String movieKhmPlaymovieId: String! } type MovieBur @model { id: ID! lang: String! module: String! part: String! page: String! url: String! pagetitle: String! playalltime: String! captions: [CaptionBur] @hasMany outurl: String outurltitle: String movieBurPlaymovieId: String! } type MovieBen @model { id: ID! lang: String! module: String! part: String! page: String! url: String! pagetitle: String! playalltime: String! captions: [CaptionBen] @hasMany outurl: String outurltitle: String movieBenPlaymovieId: String! } type CaptionEn @model { id: ID! lang: String! module: String! part: String! page: String! content: Int startTime: String endTime: String body: String movie: MovieEn @belongsTo movieEnCaptionsId: String! } type CaptionInd @model { id: ID! lang: String! module: String! part: String! page: String! content: Int startTime: String endTime: String body: String movie: MovieInd @belongsTo movieIndCaptionsId: String! } type CaptionVn @model { id: ID! lang: String! module: String! part: String! page: String! content: Int startTime: String endTime: String body: String movie: MovieVn @belongsTo movieVnCaptionsId: String! } type CaptionTha @model { id: ID! lang: String! module: String! part: String! page: String! content: Int startTime: String endTime: String body: String movie: MovieTha @belongsTo movieThaCaptionsId: String! } type CaptionTgl @model { id: ID! lang: String! module: String! part: String! page: String! content: Int startTime: String endTime: String body: String movie: MovieTgl @belongsTo movieTglCaptionsId: String! } type CaptionRus @model { id: ID! lang: String! module: String! part: String! page: String! content: Int startTime: String endTime: String body: String movie: MovieRus @belongsTo movieRusCaptionsId: String! } type CaptionNep @model { id: ID! lang: String! module: String! part: String! page: String! content: Int startTime: String endTime: String body: String movie: MovieNep @belongsTo movieNepCaptionsId: String! } type CaptionKhm @model { id: ID! lang: String! module: String! part: String! page: String! content: Int startTime: String endTime: String body: String movie: MovieKhm @belongsTo movieKhmCaptionsId: String! } type CaptionBur @model { id: ID! lang: String! module: String! part: String! page: String! content: Int startTime: String endTime: String body: String movie: MovieBur @belongsTo movieBurCaptionsId: String! } type CaptionBen @model { id: ID! lang: String! module: String! part: String! page: String! content: Int startTime: String endTime: String body: String movie: MovieBen @belongsTo movieBenCaptionsId: String! }
3. プッシュとauth
amplify push
すると、authのフローが始まる。
? Are you sure you want to continue? Yes
Do you want to use the default authentication and security configuration? Manual configuration
Select the authentication/authorization services that you want to use: User Sign-Up, Sign-In, connected with AWS IAM controls (Enables per-user Storage features for images or other content, Analyti cs, and more)
Provide a friendly name for your resource that will be used to label this category in the project: (そのままenter)
Enter a name for your identity pool. (そのままenter)
Allow unauthenticated logins? (Provides scoped down permissions that you can control via AWS IAM) No
Do you want to enable 3rd party authentication providers in your identity pool? No
Provide a name for your user pool: (そのままenter)
How do you want users to be able to sign in? Username
Do you want to add User Pool Groups? Yes
? Provide a name for your user pool group: Admin
? Do you want to add another User Pool Group No
✔ Sort the user pool groups in order of preference · Admin
Do you want to add an admin queries API? No
Multifactor authentication (MFA) user login options: OFF
Email based user registration/forgot password: Enabled (Requires per-user email entry at registration)
Specify an email verification subject: Your verification code
Specify an email verification message: Your verification code is {####}
Do you want to override the default password policy for this User Pool? No
What attributes are required for signing up? Email
Specify the app's refresh token expiration period (in days): 7
Do you want to specify the user attributes this app can read and write? No
Do you want to enable any of the following capabilities? (何も選ばずそのままenter)
Do you want to use an OAuth flow? No
ここでやっとLambdaとの連携話が登場!
? Do you want to configure Lambda Triggers for Cognito? Yes
? Which triggers do you want to enable for Cognito Post Confirmation
? What functionality do you want to use for Post Confirmation Create your own module
? Do you want to edit your custom function now? Yes
これで、Lambda用のcustom.jsが立ち上がるので、以下の通り入れる。
var aws = require('aws-sdk'); var ddb = new aws.DynamoDB(); exports.handler = async (event, context) => { let date = new Date(); if (event.request.userAttributes.sub) { let params = { Item: { 'id': {S: event.request.userAttributes.sub}, '__typename': {S: 'User'}, 'username': {S: event.userName}, 'email': {S: event.request.userAttributes.email}, 'createdAt': {S: date.toISOString()}, 'updatedAt': {S: date.toISOString()}, }, TableName: process.env.USERTABLE }; // Call DynamoDB try { await ddb.putItem(params).promise() console.log("Success"); } catch (err) { console.log("Error", err); } console.log("Success: Everything executed correctly"); context.done(null, event); } else { // Nothing to do, the user's email ID is unknown console.log("Error: Nothing was written to DynamoDB"); context.done(null, event); } };
上記が立ち上がると
? Do you want to generate code for your newly created GraphQL API Yes
GraphQL endpoint: https://5oessai6vbfgdfwc7kcgmydika.appsync-api.ap-northeast-1.amazonaws.com/graphql
GraphQL API KEY: da2-w7uygek4yjhutlsyyuqbq2uihq
4. Amplifyのコンソール画面から
amplify console
「AppSyncで表示」をクリック