• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

如何使用AWS Amplify构建无服务器GraphQL和REST API


如何使用AWS Amplify构建无服务器GraphQL和REST API  第1张

在这篇文章中,我们将进一步使用 reactaws 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,PUSHDELETE操作。因为我们的数据库中还没有任何数据,所以我们将创建一个突变来创建一个新的餐厅项目。

为此,我们将导入 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'

接下来,我们定义一个突变来创建一家餐厅。我们指定突变接受名称和描述,并命名为 createRestaurantRestaurant当我们创建上面的模式时,这个突变是自动定义的。请注意,突变是在 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 中查询数据。我们将分三步实现:

  1. 定义查询

  2. 应用加载时执行查询

  3. 将查询结果保存在我们的状态中并在 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 api
    • 执行 GraphQL 突变
    • 运行 GraphQL 查询
    • 实时数据订阅
  • 使用 AWS Lambda 创建 REST API
      • 从客户端查询 REST API
    • 从 CLI 更新 Lambda 函数
  • 结论