在这篇文章中,我们将进一步使用 react 和 aws Amplify,探索托管 graphql 数据层和 lambda 函数等特性。
添加 GraphQL api
让我们看看如何将 AWS AppSync GraphQL API 添加到我们的项目并从我们的项目中开始使用它。
我们将创建的 API 将是一个餐厅 API,用于跟上我们喜欢或想去的餐厅。
要将 GraphQL API 添加到我们的项目中,我们可以使用以下命令:
amplify add api
系统将提示您回答一些配置问题。选择以下选项:
服务类型: GraphQL
API 名称: TutsGraphQLAPI
授权类型: API 密钥
带注释的 GraphQL 架构: N
引导模式创建: Y
什么最能描述您的项目? 带有字段的单个对象(例如带有 ID、名称、描述的“Todo”)
您现在要编辑架构吗? 是
出现提示时,将架构更新为以下内容,然后保存文件:
// located at amplify-web-app/amplify/backend/api/TutsGraphQLAPI/schema.graphql type restaurant @model { id: ID! name: String! description: String }
这只是创建了一个单一的数据类型——带有Restaurant
必需的 id 和 name 字段以及可选的描述。
接下来,让我们将更新推送到我们的帐户:
amplify push
现在,API 已创建!
这里刚刚发生了什么?AWS Amplify 使用内置的 GraphQL 转换 库来创建完整的 GraphQL API,包括额外的架构、解析器和数据源。
要在创建后随时查看新的 AWS AppSync API,您可以转到位于 https://console.aws.amazon.com/appsync的控制面板 并单击刚刚创建的 API(确保您的区域是设置正确)。在 AWS AppSync 控制面板中,您可以查看 API 配置并对 API 执行查询和变更。
执行 GraphQL 突变
接下来,让我们从我们的 React 应用程序中与 API 进行交互。
我们想做的第一件事是创建一个突变。在 GraphQL 中,突变相当于 REST 的PUT
,PUSH
和DELETE
操作。因为我们的数据库中还没有任何数据,所以我们将创建一个突变来创建一个新的餐厅项目。
为此,我们将导入 API
和 graphqlOperation
从 AWS Amplify,定义一个突变,然后执行该突变。
让我们看一个实现突变的示例应用程序。在App.js
中,首先我们导入 React、我们的应用程序css和必要的 AWS Amplify 组件。
import React, { Component } from 'react'; import './App.css'; import { withAuthenticator } from 'aws-amplify-react' import { API, graphqlOperation } from 'aws-amplify'
接下来,我们定义一个突变来创建一家餐厅。我们指定突变接受名称和描述,并命名为 createRestaurant
。Restaurant
当我们创建上面的模式时,这个突变是自动定义的。请注意,突变是在 GraphQL 中指定的——一种特定于领域的查询语言。
const CreateRestaurant = ` mutation($name: String!, $description: String) { createRestaurant(input: { name: $name description: $description }) { id name description } } `
现在,我们创建我们的应用程序组件。
class App extends Component { //create initial state state = {name: '', description: ''} //update state when user types into inputs onChange = e => { this.setState({ [e.target.name]: e.target.value }) } //define function to execute mutation //render the component }
接下来,仍然在App
组件中,我们定义了一个函数来执行突变。这通过调用API.graphql
,传入突变和数据来执行突变。
//define function to execute mutation createRestaurant = async() => { if (this.state.name === '' || this.state.description === '') return try { const restaurant = { name: this.state.name, description: this.state.description } await API.graphql(graphqlOperation(CreateRestaurant, restaurant)) this.setState({ name: '', description: '' }) console.log('restaurant successfully created!') } catch (err) { console.log('error creating restaurant...') } }
然后我们渲染组件,连接我们的更改处理程序和突变函数。
//render the component render() { return ( <div className="App"> <input value={this.state.name} onChange={this.onChange} name='name' /> <input value={this.state.description} onChange={this.onChange} name='description' /> <button onClick={this.createRestaurant}>Create Restaurant</button> </div> ) }
最后,我们通过身份验证导出App
组件。
export default withAuthenticator(App, { includeGreetings: true });
您应该能够运行此代码并开始在 API 中创建新的餐厅商品。
要查看实际数据源以查看数据是否存在,请打开 AWS AppSync 控制面板,选择您的 API,单击左侧菜单中的数据源,然后单击资源名称。这将打开 Amazon DynamoDB 表。在表中,您可以查看Items选项卡中的数据。
运行 GraphQL 查询
接下来,我们看看如何从 API 中查询数据。我们将分三步实现:
定义查询
应用加载时执行查询
将查询结果保存在我们的状态中并在 UI 中呈现
首先,让我们定义查询一个新的组件。再一次,我们使用 GraphQL 语言来指定查询。我们使用的 是在推送模式listRestaurants
时自动定义的查询 。Restaurants
下面的代码片段指定我们需要一个项目列表,每个项目都有一个 id、名称和描述。
const ListRestaurants = ` query { listRestaurants { items { id name description } } }
接下来,我们需要添加一些额外的初始状态来保存从服务器返回的餐厅数组。
state = { name: '', description: '', restaurants: [] }
我们还需要添加一个componentDidMount
生命周期事件来从 GraphQL 服务器查询数据。当服务器返回餐厅列表时,此异步方法将更新组件状态。
async componentDidMount() { try { const restaurants = await API.graphql(graphqlOperation(ListRestaurants)) console.log('restaurants: ', restaurants) this.setState({ restaurants: restaurants.data.listRestaurants.items }) } catch (err) { console.log('error fetching data: ', err) } }
最后,我们将创建一个将restaurants
数组从组件状态映射到 html 的组件。
{ this.state.restaurants.map((r, i) => ( <div key={i}> <p>{r.name}</p> <p>{r.description}</p> </div> )) }
现在,当我们运行应用程序时,我们会看到来自 API 的数据正在屏幕上的列表中呈现。但是,当数据更新时,应用程序不会显示任何更改——例如,当您添加新餐厅时。
因此,对于初学者,让我们更新 createRestaurant
方法以提供对 UI 的乐观响应。现在,当我们创建一个新项目时,数据库会更新,但 UI 还不知道新项目。为了解决这个问题,我们将 createRestaurant
通过将新项目添加到数组来更新方法中的餐厅数组:
createRestaurant = async() => { if (this.state.name === '' || this.state.description === '') return try { const restaurant = { name: this.state.name, description: this.state.description } const restaurants = [...this.state.restaurants, restaurant] this.setState({ name: '', description: '', restaurants }) await API.graphql(graphqlOperation(CreateRestaurant, restaurant)) console.log('restaurant successfully created!') } catch (err) { console.log('error creating restaurant...') } }
实时数据订阅
接下来,我们希望能够处理实时数据。在 GraphQL 中,订阅允许您实时监听数据。当有新数据可用时,会触发订阅,并通过订阅传递新数据。由我们在客户端处理这些新数据。
在我们的应用程序中,我们将订阅餐厅数组,并且我们将创建一个 onCreateRestaurant
订阅,该订阅将在创建新餐厅时触发。然后,我们将从订阅中获取新项目,更新我们现有的数组,并调用 setState
以使用新数据重新渲染 UI。
就像突变和查询一样,我们首先用 GraphQL 领域特定语言定义订阅。
// define the subscription const OnCreateRestaurant = ` subscription { onCreateRestaurant { id name description } } `
订阅将在 componentDidMount
我们已经设置的 GraphQL 查询之前或之后在生命周期方法中创建:
async componentDidMount() { try { const restaurants = await API.graphql(graphqlOperation(ListRestaurants)) console.log('restaurants: ', restaurants) this.setState({ restaurants: restaurants.data.listRestaurants.items }) } catch (err) { console.log('error fetching data: ', err) } API.graphql(graphqlOperation(OnCreateRestaurant)) .subscribe({ next: eventData => { const data = eventData.value.data.onCreateRestaurant console.log('data: ', data) const restaurants = [ ...this.state.restaurants.filter(r => r.name !== data.name && r.description !== data.description), data ] this.setState({ restaurants }) } }) }
现在,如果您打开两个浏览器窗口,您应该能够在一个屏幕中创建一个突变,并在所有其他屏幕上看到更新发生。
如果您查看 .filter
我们在订阅中创建新餐厅数组时使用的方法,您会发现我们正在检查是否存在包含相同名称和描述的重复项。在生产环境中执行此操作的更好方法可能是创建一个唯一的客户端 ID,该 ID 也存储在数据库中并基于该标识符进行过滤。
使用 AWS Lambda 创建 REST API
GraphQL 是一项很棒的前沿技术,但有时我们的项目会要求我们创建一个传统的 REST API。借助 AWS Lambda 和 Amplify,还可以轻松使用 CLI 创建无服务器 REST API。
当我们创建 GraphQL API 时,我们使用了该 amplify create api
命令。该命令为我们提供了创建 GraphQL API 或 REST API 的选项。REST API 可以配置为使用独立的无服务器 Express 函数或预先配置为与 Amazon DynamoDB CRUD 操作一起使用的无服务器javascript函数。
我们将用于此 API 的选项是无服务器 Express 函数。
让我们继续添加新功能:
amplify add api
像往常一样,这将提示您填写一些配置详细信息。提供以下选项:
服务类型: REST
输入将在项目中使用的资源名称:例如 amplifyrestapi
输入 REST 端点的路径:例如 /people
Lambda 源: 创建新的 Lambda 函数
AWS Lambda 函数名称: amplifyrestapifunction
函数模板: Serverless express 函数(与 Amazon API Gateway 集成)
现在编辑本地 lambda 函数? 是
现在,您将能够在本地编辑 lambda 函数。在文件中,我们将现有方法替换为以下内容:app.get('/people')
// amplify-web-app/amplify/backend/function/amplifyrestapi/src/app.js app.get('/people', function(req, res) { const people = [ { name: "Nader" }, { name: "Amanda" }, { name: "Chris" }, { name: "" } ] res.json({ success: true, people }) });
这只是返回一个用于演示目的的常量列表。保存此文件,然后继续以下答案:
限制 API 访问? 是的
谁应该有权访问? 仅限经过身份验证的用户
您希望经过身份验证的用户获得什么样的访问权限? 读
添加另一个路径? ñ
这在本地创建了一个新的 Lambda 函数,我们将能够根据需要更新并推送到我们的账户。此 lambda 函数的代码位于 amplify/backend/function/amplifyrestapi/src。
现在,让我们将更新推送到我们的帐户:
amplify push
从客户端查询 REST API
现在,我们的 Lambda 函数已启动并运行,我们可以开始与之交互了!
首先,让我们从新 API 中查询数据并将其显示在我们的 UI 中。为此,我们将使用 Amplify 中的 API 类,调用 API.get
. 在上一节中,我们曾经 API.graphql
向 GraphQL API 发出请求,但 API 类中有许多可用的方法。您可以在官方文档中了解更多关于 API 类的信息。
import { API } from 'aws-amplify' // 1. in the initial state, create an empty array of people state = { people: [] } // 2. in componentDidMount, we will fetch this data using the API class try { const peopleData = await API.get('amplifyrestapi', '/people') this.setState({ people: peopleData.people }) } catch (err) { console.log('error fetching from Lambda API') } // 3. render the people data to the UI in the render method { this.state.people.map((person, index) => ( <p key={index}>{person.name}</p> )) }
现在,我们应该能够运行应用程序,从我们的 API 中获取人员数据,并将其呈现到屏幕上。
从 CLI 更新 Lambda 函数
除了创建新的 Lambda 函数,我们还可以从 CLI 更新我们的 Lambda 函数。
让我们更改函数以访问 API 并获取数据,而不是硬编码常量。为此,我们将使用 ax ios 库发出 HTTP 请求,并从 Star Wars API获取数据。
要使用 axios,我们需要导航到 amplify/backend/function/amplifyrestapi/src 并在那里安装它。Axios 安装在 Lambda 函数的项目文件夹中,而不是主应用程序文件夹中,因为它将在 Lambda 函数服务器端运行。
yarn add axios # or npm install axios
现在安装了 axios ,我们将更新 Lambda 函数以从 Star Wars API 获取数据:
var axios = require('axios') app.get('/people', function(req, res) { axios.get('https://swapi.co/api/people/') .then(response => { res.json({ success: true, people: response.data.results }) }) .catch(error => { res.json({ success: false, error }) }) });
现在,保存文件并 amplify push
从主项目文件夹运行以更新云中的 Lambda 函数:
amplify push
现在,我们的 API 已更新并准备就绪!
当我们刷新应用程序时,我们现在应该会看到从 Star Wars API 返回的数据。
结论
在本系列中,您学习了如何开始使用 AWS Amplify 并将其添加到您的 React 项目,以及如何添加身份验证、存储、托管和 GraphQL 或 REST API — 所有这些都无需手动编码或预置服务器. 这对应用程序开发人员来说是很大的力量!
- 执行 GraphQL 突变
- 运行 GraphQL 查询
- 实时数据订阅
- 从客户端查询 REST API
- 从 CLI 更新 Lambda 函数