GraphQL Recipes (V2) - 使用 GraphQL Transform 构建 API

2025-05-27

GraphQL Recipes (V2) - 使用 GraphQL Transform 构建 API

这是该帖子的V2,更新了新的模式和 Amplify 的最新指令。

封面照片由Tarn Nguyen 在 Unsplash 上拍摄

要查看仅包含代码和部署这些应用程序的说明的 repo,请单击此处

在我的文章《GraphQL 和全栈无服务器时代的基础设施即代码》中,我展示了如何利用 GraphQL、AWS Amplify CLIGraphQL Transform库来构建、共享和部署全栈云应用程序。

在这篇文章中,我创建了带注释的 GraphQL 模式,您可以使用它来部署流行类型的应用程序。


GraphQL Transform允许您使用 GraphQL 架构指令部署具有 NoSQL 数据库、身份验证、弹性搜索引擎、lambda 函数解析器、关系、授权等功能的 AWS AppSync GraphQL API。

例如,采用以下利用该@model指令的模式:

type Note @model {
  id: ID!
  name: String!
  description: String
}
Enter fullscreen mode Exit fullscreen mode

该架构将部署以下内容:

  1. GraphQL API
  2. 此基本类型的 CRUD GraphQL 操作:创建、读取、更新、删除和列出
  3. GraphQL 订阅(由突变事件触发;创建、更新、删除)
  4. DynamoDB NoSQL 数据库
  5. GraphQL 解析器将 DynamoDB 表映射到 GraphQL CRUD 操作

截至本文为止,GraphQL Transform 库提供了 8 条指令:

@model
// Deploys DynamodDB table + resolvers + additional GraphQL schema

@auth
// Allows the definition of auth rules and builds corresponding GraphQL resolvers based on these rules

@connection
// Enables you to specify relationships between `@model` object types 

@searchable
// Handles streaming the data of an @model object type to Amazon Elasticsearch Service and configures search resolvers that search that information

@function
//  Allows you to quickly & easily configure AWS Lambda resolvers within your AWS AppSync API

@key
// Enables you to configure custom data access patterns for @model types

@versioned
// Adds object versioning and conflict resolution to a type

@http
// Allows you to quickly configure HTTP resolvers within your AWS AppSync API
Enter fullscreen mode Exit fullscreen mode

使用此库,您可以仅使用带注释的 GraphQL 模式来部署应用程序的后端。

在这篇文章中,我将展示示例模式,当与 Amplify GraphQL 转换库一起使用时,将为许多流行类型的应用程序构建后端。

  1. 待办事项应用程序
  2. 活动应用程序
  3. 聊天应用程序
  4. 电子商务应用程序
  5. WhatsApp克隆
  6. Reddit 克隆
  7. 多用户聊天应用程序
  8. Instagram克隆
  9. 会议应用程序

有关如何使用 GraphQL 转换库部署这些应用程序的教程,请查看此处的文档。

某些应用程序可能需要针对某些订阅添加额外的自定义授权逻辑,而您可能不希望所有用户都能访问这些订阅。要了解更多信息,请查看此处的文档

测试这些

要部署任何这些应用程序,请运行以下命令:

确保首先安装 AWS Amplify CLI

$ amplify init
# Follow the steps to give the project a name, environment name, and set the default text editor.
# Accept defaults for everything else and choose your AWS Profile.

# If the app needs auth, add auth (choose the defaults)
$ amplify add auth

$ amplify add api

> Choose GraphQL
> If using authentication, choose Amazon Cognito as one of the authentication types
> Update GraphQL schema

# if the app needs storage (i.e. images or video)
$ amplify add storage

$ amplify push
Enter fullscreen mode Exit fullscreen mode

本地测试

您现在可以使用本地模拟在本地测试无服务器 GraphQL API、数据库和无服务器功能。

$ amplify mock
Enter fullscreen mode Exit fullscreen mode

观看此视频以快速了解本地测试:

待办事项应用程序

让我们从一些非常基础的东西开始:一个 Todo 应用程序。

此应用具有以下要求。用户应能够:

  1. 列出所有待办事项
  2. 创建、更新和删除 Todo

根据这些要求,我们可以假设该应用程序需要以下内容:

  1. 待办事项类型
  2. 数据库
  3. GraphQL 突变定义(创建、更新、删除待办事项)
  4. 查询的 GraphQL 定义(listTodos)
  5. 适用于所有操作的 GraphQL 解析器

为了构建此应用程序,我们可以使用以下带注释的 GraphQL 模式:

type Todo @model {
  id: ID!
  name: String!
  description: String
}
Enter fullscreen mode Exit fullscreen mode

这将部署整个 GraphQL API,包括 DynamoDB NoSQL 数据库、用于 GraphQL CRUD 和 List 操作的附加 GraphQL 模式、GraphQL 订阅以及将模式映射到数据库的 GraphQL 解析器。

活动应用程序

接下来,我们来看看如何创建一个活动应用。需要注意的是,我们需要设计一种机制,只有管理员才能创建、更新和删除活动,而普通用户或其他已登录用户(非管理员)只能读取活动。

我们还希望能够查询并获取按日期排序的事件列表。此外,还Comment可以实现一个可选类型,允许对事件进行评论,并使用指令在事件和评论之间建立一对多的关系@connection

根据这些要求,用户应该能够:

  1. 按事件日期顺序列出事件
  2. 查看单个事件
  3. 创建评论(仅限登录用户)
  4. 查看事件评论

管理员还应该能够:

  1. 创建活动
  2. 更新和删除事件

为了构建此应用程序,我们可以使用以下带注释的 GraphQL 模式:

type Event @model
  @key(name: "itemType", fields: ["itemType", "time"], queryField: "eventsByDate")
  @auth(rules: [
    { allow: groups, groups: ["Admin"] },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ]) {
    id: ID!
    name: String!
    description: String
    time: String!
    itemType: String!
    comments: [Comment] @connection #optional comments field
}

# Optional Comment type
type Comment @model
  @auth(rules: [
    { allow: owner, ownerField: "author" },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ]) {
  id: ID!
  message: String!
  author: String
}
Enter fullscreen mode Exit fullscreen mode

创建活动

创建新事件时,我们需要itemType用一致的值填充参数,以便能够按事件时间排序:

mutation createEvent {
  createEvent(input: {
    name: "Rap battle of the ages"
    description: "You don't want to miss this!"
    time: "2018-07-13T16:00:00Z"
    itemType: "Event"
  }) {
    id name description time
  } 
}
Enter fullscreen mode Exit fullscreen mode

注意:由于itemType所有项目的值(“事件”)相同,因此您还可以更新解析器请求映射模板以自动填充此值,因此无需在突变中指定它。

现在,要查询已排序的事件列表,您可以使用以下查询:

query listEvents {
  eventsByDate(itemType: "Event") {
    items {
      id
      name
      description
      time
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

通过运行创建身份验证后amplify add auth,您可以运行amplify console auth将用户添加到Admin组或使用Lambda 触发器在某些用户注册时自动执行此操作。

对事件创建评论

使用该eventCommentsId字段,您可以指定想要与评论关联的事件:

mutation createComment {
  createComment(input: {
    eventCommentsId: "7f0d82f5-b57e-4417-b515-ce04475675a2"
    message:"Amazing!"
  }) {
    id
    message
  }
}
Enter fullscreen mode Exit fullscreen mode

聊天应用

本例中我们将学习如何创建一个基本的聊天应用。想要一个更实际、能够管理多个授权用户的聊天应用,请查看多用户聊天应用示例。

此应用具有以下要求。用户应能够:

  1. 创建对话
  2. 在对话中创建消息
  3. 查看所有对话和消息
  4. 实时订阅新消息和对话
type Conversation @model {
  id: ID!
  name: String
  messages: [Message] @connection(keyName: "messagesByConversationId", fields: ["id"])
  createdAt: String
  updatedAt: String
}

type Message
  @model(subscriptions: null, queries: null)
  @key(name: "messagesByConversationId", fields: ["conversationId"]) {
  id: ID!
  conversationId: ID!
  content: String!
  conversation: Conversation @connection(fields: ["conversationId"])
  createdAt: String
}
Enter fullscreen mode Exit fullscreen mode

以下 GraphQL 查询和变异将允许用户创建对话、在对话中创建消息以及查看所有对话和消息:

mutation createConversation {
  createConversation(input: {
    name: "my first conversation"
  }) {
    name
    id
  }
}

mutation createMessage {
  createMessage(input: {
    conversationId: "your-conversation-id"
    content: "Hello world"
  }) {
    id
    content
  }
}

query listConversations {
  listConversations {
    items {
      name
      messages {
        items {
          content
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

电子商务应用程序

此应用有以下要求。客户应能够:

  1. 创建一个帐户
  2. 查看产品
  3. 创建订单
  4. 将订单项添加到订单
  5. 查看他们的帐户以及所有相关订单和物品

管理员应该能够:

  1. 创建、更新和删除产品、订单和客户
  2. 获取订单、产品和客户
  3. 根据客户 ID 获取订单

根据这些要求,我们可以假设该应用程序需要以下内容:

  1. 产品、客户、订单项和订单类型
  2. 产品、客户、行项目和订单的数据库表
  3. GraphQL 突变定义(创建、更新、删除产品、客户和订单)
  4. GraphQL 查询定义(获取、列出)
  5. 适用于所有操作的 GraphQL 解析器

为了构建此应用程序,我们可以使用以下带注释的 GraphQL 模式:

type Customer @model(subscriptions: null)
  @auth(rules: [
    { allow: owner },
    { allow: groups, groups: ["Admin"] }
  ]) {
  id: ID!
  name: String!
  email: String!
  address: String
  orders: [Order] @connection(keyName: "byCustomerId", fields: ["id"])
}

type Product @model(subscriptions: null)
  @auth(rules: [
    { allow: groups, groups: ["Admin"] },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ]) {
  id: ID!
  name: String!
  description: String
  price: Float!
  image: String
}

type LineItem @model(subscriptions: null)
  @key(name: "byOrderId", fields: ["orderId"])
  @auth(rules: [
   { allow: owner },
   { allow: groups, groups: ["Admin"] }
  ]) {
  id: ID!
  orderId: ID!
  productId: ID!
  qty: Int
  order: Order @connection(fields: ["orderId"])
  product: Product @connection(fields: ["productId"])
  description: String
  price: Float
  total: Float
}

type Order @model(subscriptions: null)
  @key(name: "byCustomerId", fields: ["customerId", "createdAt"], queryField: "ordersByCustomerId")
  @auth(rules: [
   { allow: owner },
   { allow: groups, groups: ["Admin"] }
  ]) {
  id: ID!
  customerId: ID!
  total: Float
  subtotal: Float
  tax: Float
  createdAt: String!
  customer: Customer @connection(fields: ["customerId"])
  lineItems: [LineItem] @connection(keyName: "byOrderId", fields: ["id"])
}
Enter fullscreen mode Exit fullscreen mode

您现在应该能够针对 API 执行以下 GraphQL 操作:

mutation createProduct {
  createProduct(input: {
    name: "Yeezys"
    description: "Best shoes ever"
    price: 200.00
  }) {
    id
    name
    description
    price
  }
}

mutation createCustomer {
  createCustomer(input: {
    name: "John Doe"
    email: "johndoe@myemail.com"
    address: "555 Hwy 88"
  }) {
    id
    email
    name
    address
  }
}

mutation createOrder {
  createOrder(input: {
    subtotal: 250.00
    total: 275.00
    tax: 25.00
    customerId: "some-customer-id"
  }) {
    id
    subtotal
    tax
    total
    customer {
      name
    }
  }
}

mutation createLineItem {
  createLineItem(input: {
    qty: 1
    productId: "some-product-id"
    orderId: "some-order-id"
    price: 250.00
    total: 250.00
  }) {
    id
    qty
  }
}

query getCustomer {
  getCustomer(id: "some-customer-id") {
    id
    name
    address
    orders {
      items {
        id
        lineItems {
          items {
            description
            price
            total
            qty
            product {
              id
              name
              description
            }
          }
        }
      }
    }
  }
}

query ordersByCustomerId {
  ordersByCustomerId(
    customerId: "some-customer-id"
  ) {
    items {
      id
      lineItems {
        items {
          id
          price
          total
        }
      }
      total
      subtotal
      tax
    }
  }
}

query listOrders {
  listOrders {
    items {
      id
      total
      subtotal
      tax
      lineItems {
        items {
          id
          price
          product {
            id
            price
            description
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

WhatsApp克隆

此应用有以下要求。用户应能够:

  1. 创建一个帐户
  2. 使用他们的头像图片更新他们的个人资料
  3. 创建对话
  4. 在对话中创建消息

根据这些要求,我们可以假设该应用程序需要以下内容:

  1. 用户、对话和消息类型
  2. 用户、对话和消息的数据库表
  3. GraphQL 突变定义(创建、更新、删除用户、对话和消息)
  4. 查询的 GraphQL 定义
  5. 用于实时通信的 GraphQL 订阅
  6. 适用于所有操作的 GraphQL 解析器

为了构建此应用程序,我们可以使用以下带注释的 GraphQL 模式:

type User
  @key(fields: ["userId"])
  @model(subscriptions: null)
  @auth(rules: [
    { allow: owner, ownerField: "userId" }
  ]) {
  userId: ID!
  avatar: String
  conversations: [ConvoLink] @connection(keyName: "conversationsByUserId", fields: ["userId"])
  messages: [Message] @connection(keyName: "messagesByUserId", fields: ["userId"])
  createdAt: String
  updatedAt: String
}

type Conversation
  @model(subscriptions: null)
  @auth(rules: [{ allow: owner, ownerField: "members" }]) {
  id: ID!
  messages: [Message] @connection(keyName: "messagesByConversationId", fields: ["id"])
  associated: [ConvoLink] @connection(keyName: "convoLinksByConversationId", fields: ["id"])
  members: [String!]!
  createdAt: String
  updatedAt: String
}

type Message
  @key(name: "messagesByConversationId", fields: ["conversationId"])
  @key(name: "messagesByUserId", fields: ["userId"])
  @model(subscriptions: null, queries: null) {
  id: ID!
  userId: ID!
  conversationId: ID!
  author: User @connection(fields: ["userId"])
  content: String!
  image: String
  conversation: Conversation @connection(fields: ["conversationId"])
  createdAt: String
  updatedAt: String
}

type ConvoLink
  @key(name: "convoLinksByConversationId", fields: ["conversationId"])
  @key(name: "conversationsByUserId", fields: ["userId"])
  @model(
    mutations: { create: "createConvoLink", update: "updateConvoLink" }
    queries: null
    subscriptions: null
  ) {
  id: ID!
  userId: ID!
  conversationId: ID!
  user: User @connection(fields: ["userId"])
  conversation: Conversation @connection(fields: ["conversationId"])
  createdAt: String
  updatedAt: String
}

type Subscription {
  onCreateConvoLink(userId: ID): ConvoLink
    @aws_subscribe(mutations: ["createConvoLink"])
  onCreateMessage(conversationId: ID): Message
    @aws_subscribe(mutations: ["createMessage"])
}
Enter fullscreen mode Exit fullscreen mode

Reddit 克隆

此应用有以下要求。用户应能够:

  1. 创建一个帐户
  2. 创建和删除帖子(帖子可以是图片或文本)
  3. 对帖子进行评论
  4. 对帖子进行投票
  5. 对评论进行投票

根据这些要求,我们可以假设该应用程序需要以下内容:

  1. 用户、帖子、评论和投票类型
  2. 数据库
  3. GraphQL 突变定义(创建、更新、删除用户、帖子和评论)
  4. 查询的 GraphQL 定义
  5. 适用于所有操作的 GraphQL 解析器

为了构建此应用程序,我们可以使用以下带注释的 GraphQL 模式:

type User @model(subscriptions: null)
  @key(fields: ["userId"])
  @auth(rules: [
    { allow: owner, ownerField: "userId" }
  ]) {
  userId: ID!
  posts: [Post] @connection(keyName: "postByUser", fields: ["userId"])
  createdAt: String
  updatedAt: String
}

type Post @model
  @key(name: "postByUser", fields: ["authorId", "createdAt"])
  @auth(rules: [
    { allow: owner, ownerField: "authorId" },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ]) {
  id: ID!
  authorId: ID!
  author: User @connection(fields: ["authorId"])
  postContent: String
  postImage: String
  comments: [Comment] @connection(keyName: "commentsByPostId", fields: ["id"])
  votes: [PostVote] @connection(keyName: "votesByPostId", fields: ["id"])
  createdAt: String
  voteCount: Int
}

type Comment @model
  @key(name: "commentsByPostId", fields: ["postId"])
  @auth(rules: [
    { allow: owner, ownerField: "authorId" },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ]) {
  id: ID!
  authorId: ID!
  postId: ID!
  text: String!
  author: User @connection(fields: ["authorId"])
  votes: [CommentVote] @connection(keyName: "votesByCommentId", fields: ["id"])
  post: Post @connection(fields: ["postId"])
  voteCount: Int
}

type PostVote @model
  @auth(rules: [
    { allow: owner, ownerField: "userId"},
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ])
  @key(name: "votesByPostId", fields: ["postId"]) {
  id: ID!
  postId: ID!
  userId: ID!
  post: Post @connection(fields: ["postId"])
  createdAt: String!
  vote: VoteType
}

type CommentVote @model
  @auth(rules: [
    { allow: owner, ownerField: "userId"},
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ])
  @key(name: "votesByCommentId", fields: ["commentId"]) {
  id: ID!
  userId: ID!
  commentId: ID!
  comment: Comment @connection(fields: ["commentId"])
  createdAt: String!
  vote: VoteType
}

input VoteInput {
  type: VoteType!
  id: ID!
}

enum VoteType {
  up
  down
}
Enter fullscreen mode Exit fullscreen mode

此实现将防止用户多次投票,但您必须实现自定义解析器以将投票 ID 设置为postId和用户的 的组合userId

最安全的方法是在服务器上执行此操作,通过userId从用户的 JWT 中读取用户信息。为此,您可以首先使用以下两行代码将投票 ID 设置为itemId和用户 ID 的唯一组合:

#set($itemId = "$context.identity.username#$context.args.postId")
$util.qr($context.args.input.put("id", $util.defaultIfNull($ctx.args.input.id, $itemId)))
Enter fullscreen mode Exit fullscreen mode

然后,删除或注释掉不允许覆盖投票的条件表达式代码:

#set( $condition = {
  "expression": "attribute_not_exists(#id)",
  "expressionNames": {
      "#id": "id"
  }
} )
Enter fullscreen mode Exit fullscreen mode

投票汇总

如果您想要实现投票总数或您自己选择的某种类型的算法投票计数,您可以启用 DynamoDB 触发器来调用 Lambda 函数,您可以在其中编写自己的自定义逻辑。

下面是一个实现原子计数器的 DynamoDB 触发器的示例,类似于您在需要确保投票持续增加或减少的情况下可能想要做的事情。

多用户聊天应用程序

此应用有以下要求。用户应能够:

  1. 创建一个帐户
  2. 创建对话
  3. 在对话中创建消息
  4. 查看所有对话列表
  5. 能够与其他用户创建新对话

根据这些要求,我们可以假设该应用程序需要以下内容:

  1. 用户、对话和消息类型
  2. 数据库
  3. GraphQL 突变定义(创建、更新、删除用户、对话和消息)
  4. 查询的 GraphQL 定义
  5. 适用于所有操作的 GraphQL 解析器

为了构建此应用程序,我们可以使用以下带注释的 GraphQL 模式:

type User
  @key(fields: ["userId"])
  @model(subscriptions: null)
  @auth(rules: [
    { allow: owner, ownerField: "userId" }
  ]) {
  userId: ID!
  conversations: [ConvoLink] @connection(keyName: "conversationsByUserId", fields: ["userId"])
  messages: [Message] @connection(keyName: "messagesByUserId", fields: ["userId"])
  createdAt: String
  updatedAt: String
}

type Conversation
  @model(subscriptions: null)
  @auth(rules: [{ allow: owner, ownerField: "members" }]) {
  id: ID!
  messages: [Message] @connection(keyName: "messagesByConversationId", fields: ["id"])
  associated: [ConvoLink] @connection(keyName: "convoLinksByConversationId", fields: ["id"])
  members: [String!]!
  createdAt: String
  updatedAt: String
}

type Message
  @key(name: "messagesByConversationId", fields: ["conversationId"])
  @key(name: "messagesByUserId", fields: ["userId"])
  @model(subscriptions: null, queries: null) {
  id: ID!
  userId: ID!
  conversationId: ID!
  author: User @connection(fields: ["userId"])
  content: String!
  conversation: Conversation @connection(fields: ["conversationId"])
  createdAt: String
  updatedAt: String
}

type ConvoLink
  @key(name: "convoLinksByConversationId", fields: ["conversationId"])
  @key(name: "conversationsByUserId", fields: ["userId"])
  @model(
    mutations: { create: "createConvoLink", update: "updateConvoLink" }
    queries: null
    subscriptions: null
  ) {
  id: ID!
  userId: ID!
  conversationId: ID!
  user: User @connection(fields: ["userId"])
  conversation: Conversation @connection(fields: ["conversationId"])
  createdAt: String
  updatedAt: String
}

type Subscription {
  onCreateConvoLink(userId: ID): ConvoLink
    @aws_subscribe(mutations: ["createConvoLink"])
  onCreateMessage(conversationId: ID): Message
    @aws_subscribe(mutations: ["createMessage"])
}
Enter fullscreen mode Exit fullscreen mode

Instagram克隆

此应用有以下要求。用户应能够:

  1. 创建一个帐户
  2. 创建帖子
  3. 在帖子上创建评论
  4. 关注和取消关注用户
  5. 点赞评论或帖子

根据这些要求,我们可以假设该应用程序需要以下内容:

  1. 用户、帖子、点赞、关注和评论类型
  2. 数据库
  3. GraphQL 突变定义(创建、更新、删除用户、帖子、评论、关注和喜欢)
  4. 查询的 GraphQL 定义
  5. 适用于所有操作的 GraphQL 解析器

为了构建此应用程序,我们可以使用以下带注释的 GraphQL 模式:

type User @model(subscriptions: null)
  @key(fields: ["userId"])
  @auth(rules: [
    { allow: owner, ownerField: "userId" },
    { allow: private, operations: [read] }
    ]) {
  userId: ID!
  posts: [Post] @connection(keyName: "postsByUserId", fields: ["userId"])
  createdAt: String
  updatedAt: String
  following: [Following] @connection(keyName: "followingByUserId", fields: ["userId"])
}

type Post @model
  @key(name: "postsByUserId", fields: ["authorId"])
  @auth(rules: [
    { allow: owner ownerField: "authorId" },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ]) {
  id: ID!
  authorId: ID!
  content: String!
  postImage: String
  author: User @connection(fields: ["authorId"])
  comments: [Comment] @connection(keyName: "commentsByPostId", fields: ["id"])
  likes: [PostLike] @connection(keyName: "postLikesByPostId", fields: ["id"])
}

type Comment @model
  @key(name: "commentsByPostId", fields: ["postId"])
  @auth(rules: [
    { allow: owner, ownerField: "authorId" },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ]) {
  id: ID!
  postId: ID!
  authorId: ID!
  text: String!
  likes: [CommentLike] @connection(keyName: "commentLikesByCommentId", fields: ["id"])
  author: User @connection(fields: ["authorId"])
  post: Post @connection(fields: ["postId"])
}

type PostLike @model
  @auth(rules: [
    { allow: owner, ownerField: "userId" },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ])
  @key(name: "postLikesByPostId", fields: ["postId"])
  @key(name: "postLikesByUser", fields: ["userId", "createdAt"], queryField: "likesByUser") {
  id: ID!
  postId: ID!
  userId: ID!
  user: User @connection(fields: ["userId"])
  post: Post @connection(fields: ["postId"])
  createdAt: String!
}

type CommentLike @model
  @auth(rules: [
    { allow: owner, ownerField: "userId" },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ])
  @key(name: "commentLikesByCommentId", fields: ["commentId"])
  @key(name: "commentLikesByUser", fields: ["userId", "createdAt"], queryField: "likesByUser") {
  id: ID!
  userId: ID!
  postId: ID!
  commentId: ID!
  user: User @connection(fields: ["userId"])
  post: Post @connection(fields: ["postId"])
  createdAt: String!
}

type Following @model
  @auth(rules: [
    { allow: owner, ownerField: "followerId" },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ])
  @key(name: "followingByUserId", fields: ["followerId"]) {
  id: ID
  followerId: ID!
  followingId: ID!
  follower: User @connection(fields: ["followerId"])
  following: User @connection(fields: ["followingId"])
  createdAt: String!
}
Enter fullscreen mode Exit fullscreen mode

喜欢

与 Reddit 克隆版类似,我们需要在解析器中添加一些自定义逻辑来处理点赞。要了解其工作原理,请查看Reddit 克隆版中的自定义解析器

会议应用程序

单击此处查看 Conference App in a Box,这是使用 React Native 构建的此应用程序的完整全栈版本。

此应用有以下要求。用户应能够:

  1. 创建一个帐户
  2. 查看演讲列表
  3. 查看个人演讲
  4. 对演讲发表评论
  5. (可选)报告评论

管理员应该能够:

  1. 创建、编辑和删除演讲

根据这些要求,我们可以假设该应用程序需要以下内容:

  1. 讨论、评论和(可选)报告类型
  2. 数据库
  3. GraphQL 突变定义(创建、更新、删除对话、评论和报告)
  4. 查询的 GraphQL 定义
  5. 适用于所有操作的 GraphQL 解析器

为了构建此应用程序,我们可以使用以下带注释的 GraphQL 模式:

type Talk @model
  @auth(rules: [
    { allow: groups, groups: ["Admin"] },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ]) {
  id: ID!
  name: String!
  speakerName: String!
  speakerBio: String!
  time: String
  timeStamp: String
  date: String
  location: String
  summary: String!
  twitter: String
  github: String
  speakerAvatar: String
  comments: [Comment] @connection(keyName: "commentsByTalkId", fields: ["id"])
}

type Comment @model
  @key(name: "commentsByTalkId", fields: ["talkId"])
  @auth(rules: [
    { allow: owner, ownerField: "authorId" },
    { allow: public, operations: [read] },
    { allow: private, operations: [read] }
  ])
{
  id: ID!
  talkId: ID!
  talk: Talk @connection(fields: ["talkId"])
  message: String
  createdAt: String
  authorId: ID!
  deviceId: ID
}

type Report @model
  @auth(rules: [
    { allow: owner, operations: [create, update, delete] },
    { allow: groups, groups: ["Admin"] }
  ])
  {
  id: ID!
  commentId: ID!
  comment: String!
  talkTitle: String!
  deviceId: ID
}

type ModelCommentConnection {
  items: [Comment]
  nextToken: String
}

type Query {
  listCommentsByTalkId(talkId: ID!): ModelCommentConnection
}

type Subscription {
  onCreateCommentWithId(talkId: ID!): Comment
        @aws_subscribe(mutations: ["createComment"])
}
Enter fullscreen mode Exit fullscreen mode

在此模式中,请注意,我们添加了一个额外的订阅,用于通过 ID 监听新评论。这样,我们只能订阅当前正在查看的讨论的评论。

结论

我叫Nader Dabit。我是 Amazon Web Services 的开发倡导者,负责AWS AppSyncAWS Amplify等项目。我专注于跨平台和云端应用程序开发。

文章来源:https://dev.to/open-graphql/graphql-recipes-building-apis-with-graphql-transform-3jp0
PREV
作为 Web 开发者,我最喜欢的 12 个 Chrome 扩展程序⚡🚀
NEXT
用户体验的极简主义艺术