0%

AWS AppSync GraphQL API 身份驗證與授權

之前,我們學習了 GraphQL 並創建了一個基本的 GraphQL API。 在此示例中,我們將擴展這些概念,使用 AWS AppSync 創建一個音樂節應用程序。

此應用程序將會有以下內容:

  • Amazon DynamoDB Tables,將用於存儲節目和表演廳。
  • GraphQL API 用於創建、讀取、更新、刪除、和列出節目和表演廳。
  • 只有管理員才能創建、更新、或刪除節目或表演廳。
  • 所有用戶都應該能夠查看節目和表演廳。
  • 節目與表演廳之間的關連。
  • 用戶應該能夠查看所有節目以及查看節目的詳細信息。

GraphQL、AppSync API 和 React Router

首先,我們將介紹如何為 GraphQL 類型 (Type) 之間的關係建模;如何在 GraphQL 類型和字段 (fields) 上實現授權規則;如何為 AppSync API 啟用多種授權模式,以及如何使用 React Router 啟用路由參數。

GraphQL 類型之間的關係

創建 GraphQL API 或任何 API 時,了解數據之間的建模關係非常重要,例如,我們正在構建的應用程序將具有以下兩種類型:

  • Stage
    這類型將保存各個表演廳的信息,包括表演廳名稱、和表演廳 ID。 每個表演廳也都會有許多相關的節目。
  • Performance
    這個類型將保存各個節目的信息,包括表演者、節目簡介、演出的表演廳、和表演時間。

對於這類型的 API,理想情況下,至少要具有以下的存取模式:

  • 查詢單個表演廳和該表演廳的節目
  • 查詢所有表演廳以及每個表演廳的節目。
  • 查詢個別的表演節目和相應的表演廳。
  • 查詢所有的表演節目和相應的表演廳。

現在的問題是,您如何啟用這些不同的關係和存取模式? 在我們的案例中,如何使用像 DynamoDB 這樣的 NoSQL 數據庫來做到這一點? 有兩種方法可以實現此目的:

  • 透過使用主鍵,排序鍵和本地次要索引(local secondary indexes)的組合,使 DynamoDB 中的數據模式化,從而可以使用單個表(single table)執行所有這些存取模式。 為了與 AppSync 配合使用,這必須手動並從頭開始編寫和維護所有解析器邏輯。
  • 直接在 GraphQL resolvers 解析器級別啟用這些關係。 因為我們使用的是 GraphQL,GraphQL 啟用了按字段解析器(per-field resolvers),所以可以做到這一點。 為了更好地理解這一點,讓我們看一下將要使用的 Stage 類型。
Stage type in GraphQL
1
2
3
4
5
type Stage {
id: ID!
name: String!
performances: [Performance]
}

當為此類型創建一個或多個解析器時,以下是一個示例操作鏈。假設在請求表演廳和相對應的節目時會發生這種情況:

  1. 主要的 Stage GraphQL 解析器將使用 Stage ID 從數據庫中的 Stage 表中檢索表演廳的信息。
  2. Stage 類型的 performances 字段將具有其自己的 GraphQL 解析器。該解析器使用 Stage ID 透過使用 GSI 查詢數據庫來檢索相關的節目,僅返回與該表演廳 ID 相關的節目。

Global secondary indexes(GSIs) 允許我們添加可用於查詢表並啟用其他數據存取模式的其他索引。DynamoDB 和 NoSQL 數據庫最強大的功能之一通常是建立其他索引,以實現多種存取模式 (DynamoDB 最多可擁有 20 個 GSIs)。這就像關聯式數據庫中的 indexes 與相關的 constraints (foreign key、unique index 等)。

GraphQL Transform: @connection

在之前,我們使用了 GraphQL Transform 程式庫的 @model 指令來搭建整個後端,包括解析器、數據庫和其他 GraphQL schema。 GraphQL Transform 是一個程式庫,這些指令不是 GraphQL SDL 的一部分,它使我們可以 “裝飾(decorate)” GraphQL schema,並添加其他功能。

這裡,我們將介紹幾個新的指令,包括 @connection,它使我們能夠僅用幾行代碼建立這些關係模式所需要的解析器。

多重身份驗證類型

在之前,我們使用 API key 作為身份驗證類型創建了 GraphQL API。 這在某些情況下是很好的,例如當你想讓應用程序的所有用戶都可以使用 GraphQL 查詢時。

除了 API key 外,AppSync 支援四種主要的身份驗證方法:

  • The API key
    使用 API key 時,要在發出 HTTP 請求時,在 header 以 x-api-key 的形式發送 API key。 如果使用 Amplify 客戶端,則會自動發送。
  • Amazon Cognito user pools
    在這個範例,我們要使用 Amazon Cognito 的身份驗證託管服務。 使用 Amazon Cognito,我們可以針對 API 本身以及 GraphQL 類型和字段的存取,做進階的權限和群組的控管。
  • OpenID Connect
    OpenID Connect 使你能夠使用自己的身份驗證提供者。因此,如果你喜歡其他身份驗證服務(如 Auth0),或者你的公司具有自己的身份驗證方式,則仍可以使用它來對 AppSync API 進行身份驗證。
  • IAM
    AWS IAM 類型會在 GraphQL API 上使用 AWS Signature Version 4 簽章過程。您可以使用 Cognito identity pools 中未經身份驗證的 IAM 角色給予 public 的存取權限,這會比使用 API key 啟用 public 的存取權限更安全。

這裡,我們將結合使用 API key 和 Amazon Cognito 為 API 提供的多種身份驗證類型,從而實現公共讀取和私有存取的權限控管。

授權

使用 GraphQL Transform 程式庫,我們還可以使用 @auth 指令為 API 定義不同的授權規則。

使用 @auth,我們可以定義不同類型的規則,例如:

  • 允許所有用戶創建和讀取,但僅允許創建項目的所有者可以更新和刪除。
  • 只允許特定群組的用戶能夠創建,更新或刪除。
  • 只允許所有用戶都能讀取,但不能執行任何其他操作。
  • 上述規則的組合。

在這理,我們將構建的應用程序將支援私有存取和公共的讀取。此外,我們還需要對這些規則進行更多的控管。我們需要支援以下內容:

  • 經過身份驗證而且是 Amazon Cagnito Admin 群組的用戶,將能夠執行所有操作:創建、讀取、更新、和刪除。
  • 未經身份驗證的用戶將有權訪問,但只能讀取。

使用 GSI 的自定義數據存取模式

DynamoDB 最強大的功能之一是,每個表允許 20 個額外的 GSI。 透過使用 GSI 或 GSI + sort key 的組合(也可以將其視為 filter key),你可以為數據創建極其靈活而強大的數據存取模式。 GraphQL Transform 程式庫具有 @key 指令,可輕鬆為 @model 類型配置自定義的索引結構。

我們將使用 @key 在 Performance 表上將表演廳 ID 設置為 GSI 以創建存取模式。這樣將使我們能夠在單個 GraphQL 查詢中讀取表演廳及其相關的節目表。

現在瞭解了技能概述;讓我們開始構建應用程序。

開始構建 APP

首先,我們將創建新的 React 專案,安裝依賴項,初始化新的 Amplify 應用程序以及透過 CLI 添加功能。

創建 React 專案:
yarn create react-app festivalapp

cd festivalapp

yarn add aws-amplify antd @aws-amplify/ui-react react-router-dom
初始化一個新的 Amplify 專案:
amplify init
# 請按照步驟為專案命名,環境名稱並設置預設的文本編輯器。
# 接受其他所有設置的預設值,然後選擇你的 AWS Profile。

建立後端

我們將添加的第一個功能是身份驗證。 此應用程序將需要具有基本的身份驗證,以及 Lambda 觸發器,使我們可以在用戶註冊確認後,動態的將一組預定義的用戶添加到 Admin 群組中。

Authentication

使用 auth 類別添加 Cognito 身份驗證:

amplify add auth
 Do you want to use the default authentication and security configuration? Default configuration
How do you want users to be able to sign in? Username
Do you want to configure advanced settings? Yes, I want to make some additional changes.
What attributes are required for signing up? Email
Do you want to enable any of the following capabilities? Add User to Group
? Enter the name of the group to which users will be added. Admin
? Do you want to edit your add-to-group function now? Yes

使用以下代碼更新函式,並設定 adminEmails 陣列,這個陣列就是預定義的 Admin 群組用戶:

amplify/backend/function/<function_name>/src/add-to-group.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const aws = require('aws-sdk');

exports.handler = async (event, context, callback) => {
const cognitoProvider = new aws.CognitoIdentityServiceProvider({ apiVersion: '2016-04-18' });

let isAdmin = false;
const adminEmails = ['user1@somedomain.com', 'user2@somedomain.com'];

if (adminEmails.indexOf(event.request.userAttributes.email) !== -1) {
isAdmin = true;
}

const groupParams = {
UserPoolId: event.userPoolId,
};

const userParams = {
UserPoolId: event.userPoolId,
Username: event.userName,
};

if (isAdmin) {
groupParams.GroupName = 'Admin';
userParams.GroupName = 'Admin';

try {
await cognitoProvider.getGroup(groupParams).promise();
} catch (e) {
await cognitoProvider.createGroup(groupParams).promise();
}

try {
await cognitoProvider.adminAddUserToGroup(userParams).promise();
callback(null, event);
} catch (e) {
callback(e);
}
} else {
callback(null, event)
}
};

現在,身份驗證服務已設置完畢,我們可以繼續下一步:創建 AppSync API。

The AppSync API

接下來,我們將創建 AppSync GraphQL API。 請記住,對於此 API,我們需要為公共和受保護的存取啟用多種身份驗證類型,所有這些都可以由 CLI 啟用。

我們將使用 api 類別添加 AppSync API:

amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: festivalapi
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Do you want to configure advanced settings for the GraphQL API Yes, I want to make some additional changes.
? Configure additional auth types? Yes
? Choose the additional authorization types you want to configure for the API API key
API key configuration
? Enter a description for the API key: public
? After how many days from now the API key should expire (1-365): 365
? Configure conflict detection? No
? Do you have an annotated GraphQL schema? No
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)
? Do you want to edit the schema now? (y/N) Yes

我們將使用的 GraphQL schema 有兩個主要類型: Stage 和 Performance。

amplify/backend/api/festivalapi/schema.graphql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
type Stage @model
@auth(rules: [
{ allow: public, operations: [read] },
{ allow: groups, groups: ["Admin"] }
])
{
id: ID!
name: String!
performances: [Performance] @connection(keyName: "byStageId", fields: ["id"])
}

type Performance @model
@key(name: "byStageId", fields: ["performanceStageId"])
@auth(rules: [
{ allow: public, operations: [read] },
{ allow: groups, groups: ["Admin"] }
])
{
id: ID!
performanceStageId: ID!
productId: ID
performer: String!
imageUrl: String
description: String!
time: String
stage: Stage @connection
}

讓我們看看我們使用的指令及其工作方式。

  • @auth
    首先,@auth 指令允許我們傳入一個陣列的身份驗證規則。 每個規則都有一個 allow 字段(必要)以及其他元數據(可選),包括諸如指定身份驗證提供者(如果它與預設授權類型不同)之類的事情。

    在 Stage 和 Performance 類型中,我們使用了兩種授權類型,一種用於群組存取 (groups),另一種用於公共存取 (public)。 對於 public,我們還設置 operations 陣列。 該陣列應包含我們要在 API 上啟用的操作的列表。 如果未列出任何操作,則預設情況下將啟用所有操作。

  • @key
    @key 指令使我們能夠添加 DynamoDB 表的 GSI 和對鍵進行排序。 在這個架構中,我們創建了一個名為 byStageId 的鍵,該鍵將允許我們使用 Performance 表上的 performanceStageId 字段按表演廳的 ID 查詢 Performance 表中的節目。 Stage 類型上的 performances 字段的解析器將使用該表演廳的 ID 來讀取該表演廳的所有節目。

  • @connection
    @connection 指令允許我們對類型之間的關係進行建模。 可以創建的關係類型可以是: 一對多、多對一、或多對多。 在此示例中,我們創建了兩個關係。

    • 表演廳與節目之間的關係(一個表演廳有很多表演節目)
    • 節目與表演廳之間的關係(表演節目僅屬於一個表演廳)
部署服務

配置了所有服務之後,我們就可以部署後端了:

amplify push

部署完成後,你可以隨時查詢 Amplify 專案狀態:

amplify status

Current Environment: pecftadev

| Category | Resource name | Operation | Provider plugin |
| -------- | ----------------------------------- | --------- | ----------------- |
| Function | festivalapp0ed53a88PostConfirmation | No Change | awscloudformation |
| Auth | festivalapp0ed53a88 | No Change | awscloudformation |
| Api | festivalapi | No Change | awscloudformation |

GraphQL endpoint: ...
GraphQL API KEY: ...

服務已部署,我們可以開始編寫客戶端代碼。

建立前端

我們要做的第一件事是在 src 目錄中創建此應用程序所需的程式檔:

Container.js、Footer.js、Nav.js、Admin.js、Router.js、Performance.js 、與 Home.js。

下一步是打開 src/index.js 添加 Amplify 配置,導入 Ant Design 樣式,並用即將創建的 Router 組件替換主要組件。

src/index.js
1
2
3
4
5
6
7
8
9
10
11
12
import React from 'react'
import ReactDOM from 'react-dom'
import Router from './Router'
import 'antd/dist/antd.css'
import Amplify from 'aws-amplify'
import config from './aws-exports'
Amplify.configure(config)

ReactDOM.render(
<Router />,
document.getElementById('root')
);
Container

現在,讓我們創建一個 Container 組件,該組件將用作可重用的組件,為我們的視圖添加間距與樣式:

src/Container.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react'

const Container = ({ children }) => {
return (
<div style={container}>
{ children }
</div>
)
}

const container = {
padding: '30px 40px',
minHeight: 'calc(100vh - 120px)'
}

export default Container

這裡,我們將創建 Footer 組件,該組件也是一個可重用的組件,以添加基本的頁腳,並提供一個鏈接,使管理員可以註冊和登錄:

src/Footer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from 'react'
import { Link } from 'react-router-dom'

const Footer = () => {
return (
<div style={footerStyle}>
<Link to="/admin">
Admins
</Link>
</div>
);
}

const footerStyle = {
borderTop: '1px solid #ddd',
display: 'flex',
alignItems: 'center',
padding: 20
}

export default Footer

現在,打開 src/Nav.js 創建基本的應用程序導航。 只有一個鏈接:回到主視圖的鏈接,其中將列出所有表演廳和節目表:

src/Nav.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from 'react'
import { Link } from 'react-router-dom'
import { Menu } from 'antd'
import { HomeOutlined } from '@ant-design/icons'

const Nav = ({ current }) => {
return (
<div>
<Menu selectedKeys={[current]} mode="horizontal">
<Menu.Item key='home'>
<Link to={'/'}>
<HomeOutlined />Home
</Link>
</Menu.Item>
</Menu>
</div>
)
}

export default Nav
Admin

將創建的 Admin 組件僅做三件事:允許用戶註冊、登錄、和登出。 該組件是為管理員提供一種註冊方法,以便他們可以隨後以管理員身份創建和管理 API。

請記住,當某人註冊時,如果在 Lambda 觸發器中驗證了他們的電子郵件,則他們將在註冊後被置於 Admin 群組中。 然後,他們將能夠執行 GraphQL mutations 操作來創建、更新、和刪除表演廳和節目。

如果你需要更新諸如 GraphQL schema 或 Lambda 函式之類的後端代碼,可以先在本地端進行更改,然後執行 amplify push 將更改部署到後端。

src/Admin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from 'react'
import { withAuthenticator, AmplifySignOut } from '@aws-amplify/ui-react'

const Admin = () => {
return (
<div>
<h1 style={titleStyle}>Admin</h1>
<AmplifySignOut />
</div>
)
}

const titleStyle = {
fontWeight: 'normal',
margin: '0px 0px 10px 0px'
}

export default withAuthenticator(Admin)
Router
src/Router.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React, { useState, useEffect } from 'react'
import { HashRouter, Switch, Route } from 'react-router-dom'

import Home from './Home'
import Admin from './Admin'
import Nav from './Nav'
import Footer from './Footer'
import Container from './Container'
import Performance from './Performance'

const Router = () => {
const [current, setCurrent] = useState('home')

useEffect(() => {
setRoute()
window.addEventListener('hashchange', setRoute)
return () => window.removeEventListener('hashchange', setRoute)
}, [])

function setRoute() {
const location = window.location.href.split('/')
const pathname = location[location.length - 1]
setCurrent(pathname ? pathname : 'home')
}

return (
<HashRouter>
<Nav current={current} />
<Container>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/performance/:id" component={Performance} />
<Route exact path="/admin" component={Admin} />
</Switch>
</Container>
<Footer />
</HashRouter>
)
}

export default Router

在此組件中,我們將路由器與持久性 UI 組件 Container 和 Footer 結合在一起。

這個應用程序具有三個路由:

  • Home
    這是呈現表演廳和節目的主要路由。
  • Performance
    這是呈現個別的節目和節目細節的路由。
  • Admin
    這是將為管理員提供 註冊/登錄 頁面的路由。

在 Performance 路由中,你將看到我們使用的路由如下:

/performance/:id

這是使用 URL 參數的方式,符合此路由將使我們能夠在組件本身中使用這個參數。 這很有用,透過路由參數使我們能夠使用節目的 id 來獲取節目的詳細信息。 路由參數還使我們能夠輕鬆構建支援深層鏈接的應用程序。

Performance
src/Performance.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import React, { useState, useEffect } from 'react'
import { useParams } from 'react-router-dom'
import { getPerformance } from './graphql/queries'
import { API } from 'aws-amplify'

const Performance = () => {
const [performance, setPerformance] = useState(null)
const [loading, setLoading] = useState(true)

let { id } = useParams()

useEffect(() => {
fetchPerformanceInfo()
}, [])

async function fetchPerformanceInfo() {
try {
const performanceInfo = await API.graphql({
query: getPerformance,
variables: { id },
authMode: 'API_KEY'
})
setPerformance(performanceInfo.data.getPerformance)
setLoading(false)
} catch (err) {
console.log('error fetching performance info...', err)
setLoading(false)
}
}

return (
<div>
<p>節目資訊</p>
{ loading && <h3>Loading...</h3> }
{
performance && (
<div>
<h1>{performance.performer}</h1>
<h3>{performance.time}</h3>
<p>{performance.description}</p>
</div>
)
}
</div>
)
}

export default Performance

這個組件的 render 方法非常基礎。 它只是呈現演出者、時間、和描述。 關於此組件的重點在於我們如何獲取該信息。

  1. 我們使用 useState 掛鉤創建兩個狀態:loading (預設為 true) 和 performance (預設為 null)。 我們還創建了一個名為 id 的變數,該變數使用 React Router 中的 useParams 獲取路由參數 id 的值。
  2. 加載組件時,我們使用 useEffect 掛鉤立即調用 fetchPerformanceInfo 函式。
  3. fetchPerformanceInfo 函式使用路由參數中的 id 來調用 AppSync API。 這裡的 API 調用使用 API.graphql,傳入 variables,query 和 authMode。 預設情況下,這裡的 API 使用 Cognito User Pools 作為身份驗證模式。 每當我們想覆蓋此預設 (例如在這裡的情況下進行 public API 調用) 時,我們需要在 API 調用本身中指定 authMode。
  4. 從 API 返回數據後,我們調用 setLoading 和 setPerformance 來更新 UI 以呈現從 API 返回的數據。
Home

現在,讓我們創建最後一個組件,Home 組件:

src/Home.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import React, { useState, useEffect } from 'react'
import { API } from 'aws-amplify'
import { listStages } from './graphql/queries'
import { Link } from 'react-router-dom'
import { List } from 'antd'

const Home = () => {
const [stages, setStages] = useState([])
const [loading, setLoading] = useState(true)

useEffect(() => {
getStages()
}, [])

async function getStages() {
try {
const apiData = await API.graphql({
query: listStages,
authMode: 'API_KEY'
})
const { data: { listStages: { items }}} = apiData
setStages(items)
setLoading(false)
} catch (err) {
console.log('error fetching stages list...', err)
setLoading(false)
}
}

return (
<div>
<h1 style={heading}>表演廳院</h1>
{ loading && <h2>Loading...</h2> }
{
stages.map(stage => (
<div key={stage.id} style={stageInfo}>
<p style={infoHeading}>{stage.name}</p>
<p style={infoTitle}>節目表</p>
<List
itemLayout="horizontal"
dataSource={stage.performances.items}
renderItem={performance => (
<List.Item>
<List.Item.Meta
title={<Link style={performerInfo}
to={`/performance/${performance.id}`}
>{ performance.performer }</Link>
}
description={performance.time}
/>
</List.Item>
)}
/>
</div>
))
}
</div>
)
}

const heading = { fontSize: 44, fontWeight: 300, marginBottom: 5 }
const stageInfo = { padding: '20px 0px 10px', borderBottom: '2px solid #ddd' }
const infoTitle = { fontWeight: 'bold', fontSize: 18 }
const infoHeading = { fontSize: 30, marginBottom: 5 }
const performerInfo = { fontSize: 24 }

export default Home

這個組件中的邏輯實際上與我們在 Performance 組件中所做的非常相似。

現在,應用程序已完成,但還有一件事。 因為我們為 performances 解析器創建了自定義存取模式,所以我們需要更新 listStages 查詢定義,以便也能返回與表演廳相關的節目表。 為此,使用以下命令更新 listStages 查詢:

src/graphql/queries.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
export const listStages = /* GraphQL */ `
query ListStages(
$filter: ModelStageFilterInput
$limit: Int
$nextToken: String
) {
listStages(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
name
createdAt
updatedAt
performances {
items {
id
time
performer
description
}
}
}
nextToken
}
}
`;

現在,我們可以加入一些數據。 啟動應用程序並註冊一個管理員用戶:

yarn start

單擊頁腳中的 Admins 鏈接進行註冊。

我們在這應用程序範例中沒有建立可以創建,更新或刪除表演廳與節目的 UI 介面,所以我們要直接使用 AWS AppSync 控制台來加入一些數據。註冊一個管理員用戶後,打開 AppSync 控制台:

amplify console api

選擇 GraphQL。

在控制台的 Queries 面板中,您需要單擊 Login with User Pools 然後用剛創建的用戶的 username 和 password 登錄。 當提示你輸入 ClientID 時,請使用專案的 src/aws-exports.js 文件中的 aws_user_pools_web_client_id。

接下來在 AppSync 控制台的 Queries 面板中,創建表演廳和節目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mutation createStage {
createStage(input: {
id: "stage-1"
name: "音樂廳"
}) {
id name
}
}

mutation createPerformance {
createPerformance(input: {
performanceStageId: "stage-1"
performer: "小提琴家胡乃元"
description: "與大師有約 聽見不凡聲響。活躍於國內外藝術季及演出的對位室內樂團,邀請比利時伊莉莎白女王國際音樂大賽首獎得主–小提琴家胡乃元,演奏經典的布魯赫《第一號小提琴協奏曲》"
time: "2020/11/29 (日) 15:00"
}) {
id performer description
}
}

現在,我們的數據庫具有一些數據,我們應該能夠在我們的應用程序中查看它,並在主畫面和節目詳細資訊畫面視圖之間切換導航。

在這個範例中學到了幾點:

  • GraphQL Transform 指令使你能夠向 GraphQL API 添加強大的功能,例如身份驗證規則,關係和用於其他數據存取模式的自定義索引。
  • @auth 指令允許你傳入規則陣列以定義類型和字段的授權規則。
  • @connection 指令使你可以對 GraphQL 類型之間的關係進行建模。
  • @key 指令使你能夠為自定義數據存取模式定義自定義索引並增強現有關係。
  • 當創建具有多種授權類型的 API 時,進行 API 調用時會使用預設的主要授權類型。 如果需要覆蓋主要授權類型時,可以使用 API 類 authMode 參數傳遞你要使用的授權類型。

我們完成了一個 Serverless 的應用程序,而且幾乎沒有寫到伺服端的程式碼。也不需要擔心認證、授權、與資料庫的維護、安全、與效能問題。