尝试使用AWS Amplify尝试GraphQL
接下来,我将继续使用AWS Amplify来部署React应用,并进行修正以创建一个ToDo应用程序。
基于官方教程,我将实现根据用户切换显示内容的功能。
后端实现
我們將配置Amplify的後端。
在管理用户界面中无法进行设置。
用Amplify CLI创建API。
所以,我打算放弃并利用Amplify CLI来实现GraphQL的API。
我们将使用上述的GraphQL API页面中提到的amplify add api命令来创建API。
我已经使用默认值回答了所有的问题。
amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: amplifyreact
? 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): 7
? Do you want to configure advanced settings for the GraphQL API No, I am done.
? Do you have an annotated GraphQL schema? No
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)
当API准备完成后,将询问您如下问题,请选择“Yes”作答。
(默认为“No”,即使选择“No”,只需打开amplify/backend/api/***/schema.graphql即可。)
? Do you want to edit the schema now? Yes
默认情况下,已定义了一个名为Todo的模式。 带有叹号的字段表示它们永远不会为null。 这次我们将直接使用它。
type Todo @model {
id: ID!
name: String!
description: String
}
后面我会提到,由于这个@model指令的存在,DynamoDB的设置将会自动完成。
API的部署
在这种状态下,使用amplify push命令进行API的部署。
amplify push --y
前端的实施
我会将App.js按照下面的方式进行修改。
import React, { useState, useEffect } from 'react';
import './App.css';
import { API } from 'aws-amplify';
import { withAuthenticator, AmplifySignOut } from '@aws-amplify/ui-react';
import { listTodos } from './graphql/queries';
import { createTodo as createTodoMutation, deleteTodo as deleteTodoMutation } from './graphql/mutations';
const initialFormState = { name: '', description: '' }
function App() {
const [todos, setTodos] = useState([]);
const [formData, setFormData] = useState(initialFormState);
useEffect(() => {
fetchTodos();
}, []);
async function fetchTodos() {
const apiData = await API.graphql({ query: listTodos });
setTodos(apiData.data.listTodos.items);
}
async function createTodo() {
if (!formData.name || !formData.description) return;
await API.graphql({ query: createTodoMutation, variables: { input: formData } });
setTodos([ ...todos, formData ]);
setFormData(initialFormState);
}
async function deleteTodo({ id }) {
const newTodosArray = todos.filter(todo => todo.id !== id);
setTodos(newTodosArray);
await API.graphql({ query: deleteTodoMutation, variables: { input: { id } }});
}
return (
<div className="App">
<h1>My Todos App</h1>
<input
onChange={e => setFormData({ ...formData, 'name': e.target.value})}
placeholder="Todo name"
value={formData.name}
/>
<input
onChange={e => setFormData({ ...formData, 'description': e.target.value})}
placeholder="Todo description"
value={formData.description}
/>
<button onClick={createTodo}>Create Todo</button>
<div style={{marginBottom: 30}}>
{
todos.map(todo => (
<div key={todo.id || todo.name}>
<h2>{todo.name}</h2>
<p>{todo.description}</p>
<button onClick={() => deleteTodo(todo)}>Delete Todo</button>
</div>
))
}
</div>
<AmplifySignOut />
</div>
);
}
export default withAuthenticator(App);
但是,只有当多个用户尝试登录时才会发现,尽管已经有了登录功能,但显示的内容却在所有用户之间保持一致。
基于上述应用程序,我希望能够根据每个用户将待办事项列表的内容分开。
按照每个用户将待办事项列表的内容分开。
在通常的ToDo应用中,应该显示签署用户的ToDo列表,并且只有签署的用户才能操作其内容。
实际上,要实现这一点通常需要进行授权功能的implement,可能会相当麻烦,但是在Amplify中,您可以轻松地实现它。
@auth指令
在GraphQL的模式中使用@auth指令,可以实现授权功能。
关于@auth,有官方文档可供查阅。
https://docs.amplify.aws/cli/graphql-transformer/auth
以下是对schema.graphql进行修改的方式。
- type Todo @model {
+ type Todo @model @auth(rules: [{ allow: owner }]){
id: ID!
name: String!
description: String
}
看起来需要将验证方法设置为Cognito,可以通过amplify update api修改设置。
amplify update api
? Select from the options below Update auth settings
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Configure additional auth types? No
(node:14112) ExperimentalWarning: The fs.promises API is experimental
让我们来看一下DynamoDB中的数据。
查看添加到 DynamoDB 中的数据,除了在 schema.graphql 中所记录的内容之外,还添加了一个名为 owner 的项。
拥有者授权指定用户是否可以访问或操作对象。为此,每个对象将获取ownerField字段(如果未指定,默认情况下将添加拥有者),该字段存储所有权信息,并在解析器执行过程中通过多种方式进行验证。