この記事に書いていること
AWS Amplify DataStoreに対して、複数の認証方法によるアクセス制限をかけた際にハマったポイントと解決方法を記載しました。
DataStore同期できない問題
タイトル通りですが、ローカル〜クラウド間でDataStoreの同期が取れない問題です。
スマホとwebで共通のdatastoreをもつアプリを開発した時に事件は起きました。スマホはAPI_KEY
、webはAMAZON_COGNITO_USER_POOLS
で認証を行い、それぞれアクセスレベルを分ける必要があったため、下記URLを参考にschema.graphqlの設定を追記したところ、ローカルの変更がクラウド上のDataStoreへ同期されなくなりました。
type Store @model @auth(rules: [
// Cognito Userpoolで認証されたモデルのownerはフルアクセス可能
{ allow: owner }
// APIkeyで認証された利用者は閲覧のみ可能
{ allow: public, operations: [read] }
]) {
}
ローカルではDatastoreの更新がフツーに終わり、アプリがエラーを吐かないので、問題になかなか気づかないのと、何よりデバックの手掛かりがないのが辛いところですね。
何が問題だったのか
Amplify GraphQLでは以下の認証方法をサポートしていますが、デフォルト認証に関する設定があります。
- API_KEY
- AWS_IAM
- OPENID_CONNECT
- AMAZON_COGNITO_USER_POOLS
- AWS_LAMBDA
今回のケースでは、デフォルト認証がAPI_KEY
となってました。
問題の原因としてはwebアプリからGraphQL APIにアクセスする際に認証方法を指定しておらず、デフォルトであるAPI_KEYが使用されていたため、DataStoreへの書き込みが不可となってました。
解決方法
Amplify DataStoreの更新についてはDataStore API
かGraphQL API
のどちらでもいけますが、ドキュメントを読む限りではDataStore API
には該当するOptionがなく、GraphQL API
でないと認証方法の指定ができないようです。
このため、元々DataStore API
の実装箇所をGraphQL API
で書き換え、authMode:'AMAZON_COGNITO_USER_POOLS'
を指定することで、クラウドのDataStoreへの書き込みが可能となりました。
/// Create
const todoDetails = {
text: 'This is a pen'
}
await API.graphql({
query: createToDo,
variables: {
input: todoDetails
},
/// API認証にAMAZON_COGNITO_USER_POOLSを使用
authMode: 'AMAZON_COGNITO_USER_POOLS'
});
/// Update
const todoDetails = {
id: 'some_id'
text: 'This is a apple'
/// Updata・Delete時は対象バージョンを指定する必要がある
_version: 'target_version'
}
await API.graphql({
query: updateToDo,
variables: {
input: todoDetails
},
authMode: 'AMAZON_COGNITO_USER_POOLS'
});
なお、ドキュメントにはあまり記載がないですが、Update/Deleteの際には_version
で対象バージョンを指定しないと更新失敗するので気をつけましょう。(Conflict resolver rejects mutation
というmessageのエラーが出る)
以上です。