反应来自 DynamoDB 更改的应用程序更新数据
React Application Update Data from DynamoDB Change
我正在使用 AWS AppSync 和 DynamoDB 使用 GraphQL 构建一个 React 应用程序。我的用例是,我有一个 table 数据从 DynamoDB table 中提取并使用 GraphQL 显示给用户。我有一些字段正在通过 AWS 上的步骤函数 运行 进行更新。我需要为用户自动更新这些字段,就像来自 GraphQL 的订阅一样,但我发现订阅与突变相关,因此从步骤函数更新数据库不会触发前端的订阅更新。为了解决这个问题,我使用了以下内容:
useEffect(() => {
setTimeout(getSubmissions, 5 * 1000)
})
显然,这是一种过度获取,可能会产生不必要的费用。我一直在寻找更好的解决方案并遇到 DynamoDB 流,但如果 DynamoDB 流无法触发前端来刷新组件,它们将无济于事。必须有比我想出的更好的解决方案。
谢谢!
您是正确的,在 AWS AppSync 中,要触发订阅发布,您必须触发 GraphQL 突变。
but I found out that subscriptions are tied to mutations and thus an
update to the database from step functions will not trigger a
subscription update on the frontend.
如果您直接通过步骤函数或通过 DynamoDB 流更新 DynamoDB table,则 AppSync 无法知道刷新的数据。
为什么不让步骤函数使用 AppSync 突变而不是直接更新 table?这样您就可以 link 订阅突变,并让您感兴趣的客户在数据刷新时获得推送更新。
假设您使用 Cognito 作为 AppSync 应用程序的身份验证,您可以在 dynamo table 上设置一个 lambda 触发器来生成一个 cognito 令牌,并使用它向您的突变端点发出授权请求。注意:在您的 cognito userpool>app clients 页面中,您需要选中 Enable username password auth for admin APIs for authentication (ALLOW_ADMIN_USER_PASSWORD_AUTH) 框以生成客户端密码。
const AWS = require('aws-sdk');
const crypto = require('crypto');
var jwt = require('jsonwebtoken');
const secrets = require('./secrets.js');
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
var config;
const adminAuth = () => new Promise((res, rej) => {
const digest = crypto.createHmac('SHA256', config.SecretHash)
.update(config.userName + config.ClientId)
.digest('base64');
var params = {
AuthFlow: "ADMIN_NO_SRP_AUTH",
ClientId: config.ClientId, /* required */
UserPoolId: config.UserPoolId, /* required */
AuthParameters: {
'USERNAME': config.userName,
'PASSWORD': config.password,
"SECRET_HASH":digest
},
};
cognitoidentityserviceprovider.adminInitiateAuth(params, function(err, data) {
if (err) {
console.log(err.stack);
rej(err);
}
else {
data.AuthenticationResult ? res(data.AuthenticationResult) : rej("Challenge requested, to verify, login to app using admin credentials");
}
});
});
const decode = auth => new Promise( res => {
const decoded = jwt.decode(auth.AccessToken);
auth.decoded = decoded
res(auth);
});
//example gql query
const testGql = auth => {
const url = config.gqlEndpoint;
const payload = {
query: `
query ListMembers {
listMembers {
items{
firstName
lastName
}
}
}
`
};
console.log(payload);
const options = {
headers: {
"Authorization": auth.AccessToken
},
};
console.log(options);
return axios.post(url, payload, options).then(data => data.data)
.catch(e => console.log(e.response.data));
};
exports.handler = async (event, context, callback) => {
await secrets() //some promise that returns your keys object (i use secrets manager)
.then( keys => {
#keys={ClientId:YOUR_COGNITO_CLIENT,
# UserPoolId:YOUR_USERPOOL_ID,
# SecretHash:(obtained from cognito>userpool>app clients>app client secret),
# gqlEndpoint:YOUR_GRAPHQL_ENDPOINT,
# userName:YOUR_COGNITO_USER,
# password:YOUR_COGNITO_USER_PASSWORD,
# }
config = keys
return adminAuth()
})
.then(auth => {
return decode(auth)
})
.then(auth => {
return testGql(auth)
})
.then( data => {
console.log(data)
callback(null, data)
})
.catch( e => {
callback(e)
})
};
我正在使用 AWS AppSync 和 DynamoDB 使用 GraphQL 构建一个 React 应用程序。我的用例是,我有一个 table 数据从 DynamoDB table 中提取并使用 GraphQL 显示给用户。我有一些字段正在通过 AWS 上的步骤函数 运行 进行更新。我需要为用户自动更新这些字段,就像来自 GraphQL 的订阅一样,但我发现订阅与突变相关,因此从步骤函数更新数据库不会触发前端的订阅更新。为了解决这个问题,我使用了以下内容:
useEffect(() => {
setTimeout(getSubmissions, 5 * 1000)
})
显然,这是一种过度获取,可能会产生不必要的费用。我一直在寻找更好的解决方案并遇到 DynamoDB 流,但如果 DynamoDB 流无法触发前端来刷新组件,它们将无济于事。必须有比我想出的更好的解决方案。
谢谢!
您是正确的,在 AWS AppSync 中,要触发订阅发布,您必须触发 GraphQL 突变。
but I found out that subscriptions are tied to mutations and thus an update to the database from step functions will not trigger a subscription update on the frontend.
如果您直接通过步骤函数或通过 DynamoDB 流更新 DynamoDB table,则 AppSync 无法知道刷新的数据。 为什么不让步骤函数使用 AppSync 突变而不是直接更新 table?这样您就可以 link 订阅突变,并让您感兴趣的客户在数据刷新时获得推送更新。
假设您使用 Cognito 作为 AppSync 应用程序的身份验证,您可以在 dynamo table 上设置一个 lambda 触发器来生成一个 cognito 令牌,并使用它向您的突变端点发出授权请求。注意:在您的 cognito userpool>app clients 页面中,您需要选中 Enable username password auth for admin APIs for authentication (ALLOW_ADMIN_USER_PASSWORD_AUTH) 框以生成客户端密码。
const AWS = require('aws-sdk');
const crypto = require('crypto');
var jwt = require('jsonwebtoken');
const secrets = require('./secrets.js');
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
var config;
const adminAuth = () => new Promise((res, rej) => {
const digest = crypto.createHmac('SHA256', config.SecretHash)
.update(config.userName + config.ClientId)
.digest('base64');
var params = {
AuthFlow: "ADMIN_NO_SRP_AUTH",
ClientId: config.ClientId, /* required */
UserPoolId: config.UserPoolId, /* required */
AuthParameters: {
'USERNAME': config.userName,
'PASSWORD': config.password,
"SECRET_HASH":digest
},
};
cognitoidentityserviceprovider.adminInitiateAuth(params, function(err, data) {
if (err) {
console.log(err.stack);
rej(err);
}
else {
data.AuthenticationResult ? res(data.AuthenticationResult) : rej("Challenge requested, to verify, login to app using admin credentials");
}
});
});
const decode = auth => new Promise( res => {
const decoded = jwt.decode(auth.AccessToken);
auth.decoded = decoded
res(auth);
});
//example gql query
const testGql = auth => {
const url = config.gqlEndpoint;
const payload = {
query: `
query ListMembers {
listMembers {
items{
firstName
lastName
}
}
}
`
};
console.log(payload);
const options = {
headers: {
"Authorization": auth.AccessToken
},
};
console.log(options);
return axios.post(url, payload, options).then(data => data.data)
.catch(e => console.log(e.response.data));
};
exports.handler = async (event, context, callback) => {
await secrets() //some promise that returns your keys object (i use secrets manager)
.then( keys => {
#keys={ClientId:YOUR_COGNITO_CLIENT,
# UserPoolId:YOUR_USERPOOL_ID,
# SecretHash:(obtained from cognito>userpool>app clients>app client secret),
# gqlEndpoint:YOUR_GRAPHQL_ENDPOINT,
# userName:YOUR_COGNITO_USER,
# password:YOUR_COGNITO_USER_PASSWORD,
# }
config = keys
return adminAuth()
})
.then(auth => {
return decode(auth)
})
.then(auth => {
return testGql(auth)
})
.then( data => {
console.log(data)
callback(null, data)
})
.catch( e => {
callback(e)
})
};