每个Prisma服务都公开一个GraphQL API,其中包含CRUD和服务数据模型中定义的类型的实时操作。 此API称为 Prisma API

定义Prisma API的类型和操作的GraphQL schema称为 Prisma GraphQL schema。 它由Prisma自动生成。

试试的Prisma的playground

点击这里试试在GraphQL playground 中的Prisma API。

所述Prisma API是基于以下的数据模型:


type Post {
  id: ID! @unique
  createdAt: DateTime!
  updatedAt: DateTime!
  isPublished: Boolean! @default(value: "false")
  title: String!
  text: String!
  author: User!
}
type User {
  id: ID! @unique
  email: String! @unique
  password: String!
  name: String!
  posts: [Post!]!
}

本章介绍所有你需要了解的Prisma API,以及如何可以在各种环境中使用。

本节解释了一些重要的概念,以了解Prisma API。

除非另有说明,本页上的例子是基于以下数据模型的Prisma API:


type User {
  id: ID! @unique
  email: String @unique
  name: String!
  posts: [Post!]!
}
type Post {
  id: ID! @unique
  title: String!
  published: Boolean! @default(value: "false")
  author: User
}

Prisma数据库是定义Prisma API的数据类型和操作的GraphQL schema。 它是自动生成的,并为service的数据模型中指定的模型指定CRUD和实时操作。

Prisma API中的许多操作仅影响现有节点的子集,有时仅影响单个节点,例如更新或删除节点。

在这些情况下,你需要一种方法来询问API中的特定节点。 这就是where过滤器参数的用途。 它允许你指定用于选择应应用操作的节点的条件。

可以通过使用@unique指令注释的任何字段选择节点。

以下是需要选择节点的几种情况。

通过其email检索单个User节点:


query {
  user(where: {
    email: "alice@prisma.io"
  }) {
    id
  }
}

{
  "data": {
    "user": {
      "id": "cjkawhcz44a4c0a84un9a86wt"
    }
  }
}

更新单个POST节点的title:


mutation {
  updatePost(
    where: {
      id: "ohco0iewee6eizidohwigheif"
    }
    data: {
      title: "GraphQL is awesome"
    }
  ) {
    id
  }
}

{
  "data": {
    "updatePost": {
      "id": "ohco0iewee6eizidohwigheif"
    }
  }
}

一次性完成对POST节点的批量更新published(见[批量Mutation(#批量Mutation)):


mutation {
  updateManyPosts(
    where: {
      id_in: ["ohco0iewee6eizidohwigheif", "phah4ooqueengij0kan4sahlo", "chae8keizohmiothuewuvahpa"]
    }
    data: {
      published: true
    }
  ) {
    count
  }
}

{
  "data": {
    "updateManyPosts": {
      "count": 3
    }
  }
}

节点选择概念的一个应用是Prisma API暴露的批量Mutation。 批量更新或删除已经过优化,可以更改大量节点。 因此,这些Mutation仅返回受影响的节点数,而不是特定节点上的完整信息。

例如,MutationupdateManyPostsdeleteManyPosts提供了一个where参数来选择特定节点,并返回一个带有受影响节点数的count字段(参见例子)。


mutation {
  deleteManyUsers(
    where: {
      email_in: ["alice@prisma.io", "bob@prisma.io"]
    }
  ) {
    count
  }
}

{
  "data": {
    "deleteManyUsers": {
      "count": 2
    }
  }
}

PRISMA提供两种方法通过关系字段检索节点列表:

  • 简单的关系查询(direct节点检索):

    
    query {
      posts {
        id
        title
        published
      }
    }
    
  • Connection的查询:

    
    query {
      postsConnection {
        edges {
          node {
            id
            title
            published
          }
        }
      }
    }
    

与直接返回节点列表的简单关系查询相比,连接查询基于Relay Connection模型。 除了分页信息之外,Prisma API中的连接还具有高级功能,如聚合。

例如,虽然posts查询允许你选择特定的Post节点,按某些字段对它们进行排序并对结果进行分页,但postsConnection查询还允许你计算所有未发布的帖子:


query {
  postsConnection {
    # `aggregate` 允许执行常见的聚合操作
    aggregate {
      count
    }
    edges {
      # 每个“node”指的是一个“Post”节点
      node {
        title
      }
    }
  }
}

{
  "data": {
    "postsConnection": {
      "aggregate": {
        "count": 1
      },
      "edges": [
        {
          "node": {
            "title": "Watch all the talks from GraphQL Europe: bit.ly/gql-eu"
          }
        }
      ]
    }
  }
}

查看这些功能的要求,了解即将实现的聚合操作。

Prisma API中不是批处理操作的单个Mutation总是以事务方式执行,即使它们包含许多可能分布在多个相关节点上的操作。 这对于在多种类型上执行多个数据库写入的嵌套Mutation特别有用。

嵌套Mutation是触及至少两个节点的Mutation,每个节点具有不同类型。 这是一个简单的例子:


mutation {
  createUser(data: {
    name: "Sarah"
    posts: {
      create: [
        { title: "GraphQL is great" }
        { title: "Prisma is a data access layer" }
      ],
      connect: [
        { id: "cjk1e3t7i1ark0b299pvrge5m" }
      ]
    }
  }) {
    id
    posts {
      id
    }
  }
}

这种Mutation总共涉及了 4个节点:

  • creates 1个新的User节点。
  • creates 2个POST节点。这两个POST节点也是直接connected到新的User节点。
  • connects新的User节点到1个现有POST节点。

这种Mutation总进行6个单操作:

  • Creating 1个User节点。
  • Creating 2个POST节点。
  • Connecting 3个POST节点到新的User节点。

如果上述任何一项操作的失败(例如,由于的违反@unique约束),则_全部_Mutation回滚!

Mutation是事务性的,意味着它们是原子的和孤立的。 这意味着在相同嵌套Mutation的两个单独动作之间,没有其他Mutation可以改变数据。 在处理完整Mutation之前,也不能观察到单个动作的结果。

Prisma支持数据模型中关系的不同删除行为。 有两种主要的删除行为:

  • CASCADE:当删除与一个或多个其他节点有关的节点时,也会删除这些节点。
  • SET_NULL:当删除与一个或多个其他节点有关的节点时,引用已删除节点的字段将设置为null。

如上所述,你可以为相关节点指定专用删除行为。 这就是@ relation指令的onDelete参数。

请看下面的例子:


type User {
  id: ID! @unique
  comments: [Comment!]! @relation(name: "CommentAuthor", onDelete: CASCADE)
  blog: Blog @relation(name: "BlogOwner", onDelete: CASCADE)
}
type Blog {
  id: ID! @unique
  comments: [Comment!]! @relation(name: "Comments", onDelete: CASCADE)
  owner: User! @relation(name: "BlogOwner", onDelete: SET_NULL)
}
type Comment {
  id: ID! @unique
  blog: Blog! @relation(name: "Comments", onDelete: SET_NULL)
  author: User @relation(name: "CommentAuthor", onDelete: SET_NULL)
}

让我们研究一下三种类型的删除行为:

  • 当一个User节点被删除,

    • 所有相关的Comment节点将被删除。
    • 相关Blog节点将被删除。
  • 当一个Blog节点被删除,

    • 所有相关的Comment节点将被删除。
    • 相关User节点将有其blog字段设置为null
  • 当一个Comment节点被删除,

    • 相关Blog节点继续存在,并且删除Comment节点从其comments列表中删除。
    • 相关User节点继续存在,并且删除Comment节点从其comments列表中删除。

可以使用prisma.yml中的服务secret(指定为secret属性)来保护Prisma API:


secret: my-secret-42

作为Prisma services的开发者,你可以选择自己的服务密码。当服务被使用包含secret属性prisma.yml部署,该服务的Prisma API将需要通过Service token(JWT)的认证:

获得业务令牌最简单的方法是通过在你的prisma.yml所在的同一目录中运行prisma token命令:


$ prisma token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InNlcnZpY2UiOiJkZW1vQGRldiIsInJvbGVzIjpbImFkbWluIl19LCJpYXQiOjE1MzI1ODgzNzAsImV4cCI6MTUzMzE5MzE3MH0.Nv8coqsiwdwoSfWCBJHYfnr0WK2GRyqO5xTN6Q3IVkw

将所生成的令牌复制到到所述Prisma API的HTTP请求Autorization头:


curl '__YOUR_PRISMA_ENDPOINT__' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer __YOUR_SERVICE_TOKEN__' \
--data-binary '{"query":"mutation { createUser(data: { name: "Sarah" }) { id } }"'

注意

不要将服务机密和服务“令牌”与用于保护Prisma服务器的Management API的Prisma Management API密钥混淆。

Service secret是由Prisma services的开发者指定的字母数字的随机字符串。在prisma.yml的secret属性中设置:


secret: my-secret-42

Service token遵守JSON web token(JWT)规范(RFC 7519):

"JSON Web Token"(JWT)是一种紧凑的,URL安全的方式,用于表示要在双方之间传输的声明.JWT中的声明被编码为JSON对象,用作JSON Web签名的有效负载(JWS) )结构或作为JSON Web加密(JWE)结构的明文,使声明能够通过消息验证代码(MAC)进行数字签名或完整性保护和/或加密。“

一个JWT有以下三个部分组成:

  • Header: 标头通常由两部分组成:令牌的类型,即JWT,以及正在使用的散列算法(在Prisma服务令牌的情况下为HS256)。

    
    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
  • Payload:payload包含声明。 声明是关于实体(通常是用户)和其他数据的声明。 以下是部署到dev阶段的名为demo的服务的样子:

    
    {
      "data": {
        "service": "demo@dev",
        "roles": [
          "admin"
        ]
      },
      "iat": 1532530208,
      "exp": 1533135008
    }
    }
    
  • Signature:签名用于验证消息在此过程中未发生更改。 要创建签名部分,你必须采用编码标头,编码的有效负载,秘密,标头中指定的算法,并对其进行签名。 例如,如果要使用HMAC SHA256算法,将按以下方式创建签名:

    
    HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      secret)
    

因此,JWT通常是这样的:xxxxx.yyyyy.zzzzz

了解更多关于JWTs 这里

所述JWT必须包含以下的Claims:

  • Issued atiat字段包含一个Unix时间戳,其中包含生成令牌的确切时间。
  • Expiration dateexp字段包含表示令牌到期日期的Unix时间戳。 服务令牌完全有效一周
  • Service informationdata字段是一个有两个键的对象    - service字段指定服务的namestage    - “roles”字段包含使用该令牌授予的访问权限。 将来可能会通过引入一个角色概念来支持更细粒度的访问控制,例如[“write:Log”,“read:*”]

这里有一个JWT的示例Payload:


{
  "data": {
    "service": "myservice@prod",
    "roles": [
      "admin"
    ]
  },
  "iat": 1532530208,
  "exp": 1533135008
}

该service token是_bearer_token:

_ _bearer_token:一种安全令牌,其属性是拥有该令牌的任何一方(“持票人”)可以以任何其他拥有该令牌的方式使用该令牌。 使用不记名令牌不需要持票人证明拥有加密密钥材料(占有证明)。

它需要由OAuth2.0的授权框架规格中指定要被发送到Prisma API。

当发送在/由HTTP定义的授权请求报头字段1.1 [RFC2617]的访问令牌,客户端使用的Bearer认证方案来发送访问令牌。

例如:


GET /resource HTTP/1.1
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1JqM

此方案的Authorization标头字段的语法遵循[RFC2617]第2节中定义的Basic方案的使用。 请注意,与Basic一样,它不符合[RFC2617]第1.2节中定义的通用语法,但与为HTTP 1.1 [HTTP-AUTH]开发的通用身份验证框架兼容,尽管它不遵循首选实践 其中概述的是为了反映现有的部署。 Bearer凭证的语法如下:


b64token    = 1*( ALPHA / DIGIT /
                   "-" / "." / "_" / "~" / "+" / "/" ) *"="
credentials = "Bearer" 1*SP b64token
Clients SHOULD make authenticated requests with a bearer token using the `Authorization` request header field with the `Bearer` HTTP authorization scheme. Resource servers MUST support this method.

下面是一个例子,如何保护你的Prisma API,使对请求身份验证。

假设你开始通过以下服务配置配置一个新的Prisma services:

datamodel.prisma


type User {
  id: ID! @unique
  name: String!
}

****prisma.yml


endpoint: https://eu1.prisma.sh/john-doe/demo/dev # deployed to a Prisma Demo server 
datamodel: datamodel.prisma

在这个例子中,假设该服务被部署到一个演示服务器,因此可在公共互联网上。

当使用上述服务配置部署服务时,知道服务端点的每个人都能够向其API发送查询和Mutation,这意味着他们可以有效地对你的数据库执行任意读取和写入:


curl 'https://eu1.prisma.sh/jane-doe/demo/dev' \
-H 'Content-Type: application/json' \
--data-binary '{"query":"mutation { createUser(data: { name: "Sarah" }) { id }}"}'

当使用GraphQL Playground,需要跟Prisma API请求时不需要对HTTP头进行设置。

你需要为了你的Prisma API做的唯一的事情是在prisma.yml设置服务密码:


endpoint: https://eu1.prisma.sh/john-doe/demo/dev # deployed to a Prisma Demo server 
datamodel: datamodel.prisma
secret: my-secret-42

要应用此更改,你还需要重新部署服务:


prisma deploy

如果你现在正在试图使用curl重新发送上述HTTP请求:


curl 'https://eu1.prisma.sh/jane-doe/demo/dev' \
-H 'Content-Type: application/json' \
--data-binary '{"query":"mutation { createUser(data: { name: "Sarah" }) { id }}"}'

你会收到以下错误:


{
  "errors" : [ {
    "message" : "Your token is invalid. It might have expired or you might be using a token from a different project.",
    "code" : 3015,
    "requestId" : "eu1:api:cjk28t8e55tld0b296sr2ey6v"
  } ]
}

对于针对Prisma API发出的所有请求,无论是请求的查询,Mutation还是订阅,都会发生这种情况。 如果在GraphQL Playground中未设置HTTP标头,请求将失败并显示相同的错误消息:

要解决此问题,你需要在HTTP请求的Authorization标头字段中包含服务标记。 你可以使用Prisma CLI获取服务令牌:


prisma token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InNlcnZpY2UiOiJkZW1vQGRldiIsInJvbGVzIjpbImFkbWluIl19LCJpYXQiOjE1MzI1MzAyMDgsImV4cCI6MTUzMzEzNTAwOH0.FM6haUilhi89-C-2h7asV3-Ot6NQrs1qoaKL-wPjj04

CLI打印的令牌需要在Authorization标头字段中设置,并以Bearer为前缀:


curl 'https://eu1.prisma.sh/jane-doe/demo/dev' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InNlcnZpY2UiOiJkZW1vQGRldiIsInJvbGVzIjpbImFkbWluIl19LCJpYXQiOjE1MzI1MzAyMDgsImV4cCI6MTUzMzEzNTAwOH0.FM6haUilhi89-c-2h7asV3-Ot6NQrs1qoaKL-wPjj04' \
--data-binary '{"query":"mutation { createUser(data: { name: "Sarah" }) { id }}"}'

同样地,在GraphQL Playground,你需要(JSON格式)在左下角的HTTP header窗格设置它:


{
  "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InNlcnZpY2UiOiJkZW1vQGRldiIsInJvbGVzIjpbImFkbWluIl19LCJpYXQiOjE1MzI1MzAyMDgsImV4cCI6MTUzMzEzNTAwOH0.FM6haUilhi89-c-2h7asV3-Ot6NQrs1qoaKL-wPjj04M"
}

如果你使用了PRISMA playground命令打开Playground上,Prisma的CLI自动注入了一个有效的服务标识Authorization头。

一个Prisma services的GraphQL API在Prisma的GraphQL schema中指定。Prisma GraphQL schema是基于数据模型自动生成的:

Query类型Prisma的GraphQL schema定义了所有的Prisma API接受查询。

作为一个例子,考虑下面的数据模型:


type User {
  id: ID! @unique
  name: String!
}

这是Prisma会自动生成的Query的type:


type Query {
  users(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User]!
  user(where: UserWhereUniqueInput!): User
  usersConnection(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): UserConnection!
}

对于datamodel中的每种类型,都会生成三个查询。 以上面的“User”类型为例,这些查询是:

  • user:检索单个User节点
  • users:检索User节点列表(作为一个对象查询)
  • usersConnection:检索User节点列表(作为聚合查询)

要详细检查你的Prisma API的所有可用的操作,你可以读取Prisma services的GraphQL schema。它可以用GraphQL CLI下载:


graphql get-schema --endpoint __YOUR_PRISMA_ENDPOINT__ --output prisma.graphql --no-all

了解Prisma API具体功能的另一种方法是探索GraphQL Playground中自动生成的API文档。 你可以通过单击Playground右边缘的绿色 SCHEMA - 按钮来执行此操作:

本节的所有示例查询基于此数据模型配置Prisma services:


type Post {
  id: ID! @unique
  title: String!
  published: Boolean!
  author: User!
}
type User {
  id: ID! @unique
  age: Int
  email: String! @unique
  name: String!
  accessRole: AccessRole
  posts: [Post!]!
}
enum AccessRole {
  USER
  ADMIN
}

Prisma API提供两种查询:

  • 对象查询:获取特定对象类型的单个或多个节点。
  • 聚合查询:公开聚合和“Relay”兼容连接等高级功能,实现强大的分页模型。

下面的概念也得记住有用:

  • 分层(或嵌套)查询:跨关系获取数据。
  • 查询参数:允许筛选,排序,分页等。

我们可以使用对象查询来获取无论是单个节点,或某个对象类型节点的列表

在这里,我们使用posts查询来获取POST节点列表。在响应中,我们只包括id和每个POST节点的title:


query {
  posts {
    id
    title
  }
}

我们也可以查询特定POST节点。请注意,我们使用了where参数选择节点:


query {
  post(where: {
    id: "cixnen24p33lo0143bexvr52n"
  }) {
    id
    title
    published
  }
}

因为User是在我们的数据模型另一种类型,users是另一种可用的查询。同样,我们可以使用where参数指定返回的用户条件。在这个例子中,我们筛选出age18更高的所有User节点:


query {
  users(where: {
    age_gt: 18
  }) {
    id
    name
  }
}

这也适用于跨关系。在这里,我们要提取那些节点中age18更高的authorPOST:


query {
  posts(where: {
    author: {
      age_gt: 18
    }
  }) {
    id
    title
    author {
      name
      age
    }
  }
}

对象查询直接返回节点列表。在特殊情况下,或者使用高级功能时,使用聚合查询是较好的选择。它们的附加信息(完全符合)Relay connections

Relay connections的核心思想是提供关于在数据图中的edges元信息。例如,每个edge不仅具有关于对应的对象访问信息(node),而且还有cursor,允许实现强大的基于指针的分页

在这里,我们撷取了使用postsConnection查询所有POST节点。请注意,我们还要求每个edge附带cursor:


# Fetch all posts
query {
  postsConnection {
    edges {
      cursor
      node {
        id
        title
      }
    }
  }
}

聚合查询还通过字段公开聚合功能aggregate:


#含有"GraphQL"标题的所有帖子
query {
  postsConnection(where: {
    title_contains: "GraphQL"
  }) {
    aggregate {
      count
    }
  }
}

更多聚合将随时间被添加。找到[这里]路线图的更多信息(https://github.com/prisma/prismagraphql/issues/1312)。

数据模型中的每个可用关系都会为其连接的两个模型的查询添加一个新字段。

在这里,我们取一个特定的User节点,并使用posts获取与其相关的全部POST节点:


query {
  user(where: {
    id: "cixnekqnu2ify0134ekw4pox8"
  }) {
    id
    name
    posts {
      id
      published
    }
  }
}

user.posts行为与posts查询相同,因为它允许你指定你感兴趣的Post类型的字段。

在整个Prisma API中,你将找到可以提供的查询参数,以进一步控制查询响应。它可以是以下任何一种:

  • Ordering排序:使用orderBy对任何字段值排序节点
  • Filtering过滤:使用标量或关系过滤器选择查询中的节点where
  • Pagination分页:使用firstbeforelastafter,和在查询节点切片skip

这些查询参数可以结合起来,实现非常具体的查询响应。

查询的所有节点可以提供orderBy参数的类型的每个字段:ORDERBY:<字段> _ASCORDERBY:<字段> _DESC

按title正序排序所有Post节点的列表:


query {
  posts(orderBy: title_ASC) {
    id
    title
    published
  }
}

按published倒序排序所有Post节点的列表:


query {
  posts(orderBy: published_DESC) {
    id
    title
    published
  }
}

不必在实际查询中选择要排序的字段。如果未指定排序,则会按id字段自动按顺序排序响应。

注意

这是目前无法排序的多个字段

当查询类型的所有节点上,你可以提供不同的参数给where参数根据你的要求来约束数据。可用选项取决于在相关类型上定义的标量和关系字段。

如果只为参数提供一个参数where,则查询响应将仅包含符合此约束的节点。可以使用AND/OR组合多个过滤器,有关详细信息,请参见下文。

筛选查询响应的最简单方法是为要筛选的特定字段提供具体值。

查询尚未published所有POST节点:


query {
  posts(where: {
    published: false
  }) {
    id
    title
    published
  }
}

查询所有User节点特定的name:


query {
  users(where: {
    name: "Alice"
  }) {
    id
  }
}

查询所有具有特定ageUser节点:


query {
  users(where: {
    age: 30
  }) {
    id
  }
}

根据要筛选的字段类型,你可以访问可用于筛选查询响应的不同高级条件。

查询所有POST节点,其title是一个指定的字符串:


query {
  posts(where: {
    title_in: ["My biggest Adventure", "My latest Hobbies"]
  }) {
    id
    title
    published
  }
}

查询所有User节点,其age小于42 :


query {
  users(where: {
    age_lt: 42
  }) {
    id
  }
}

对于一对一关系,你可以通过嵌入相应的参数来定义相关节点上的条件where。

查询其中authorUSER访问角色的所有POST节点:


query {
  posts(where: {
    author: {
      accessRole: USER
    }
  }) {
    title
  }
}

对于一对多关系,另外三个参数可用:everysomenone,定义的条件应符合everysomenone相关节点。

查询至少有一个Post 节点published的所有User节点:


query {
  users(where: {
    posts_some: {
      published: true
    }
  }) {
    id
    posts {
      published
    }
  }
}

对于一对一或多对多关系的嵌套参数中也可以使用关系过滤器。

查询likeauthor不是ADMIN访问角色的POST所有User节点:


query {
  users(where: {
    likedPosts_none: {
      author: {
        accessRole: ADMIN
      }
    }
  }) {
    name
  }
}

likedPosts不是上述数据模型的一部分,但可以很容易地通过将相应字段添加到User:likedPosts: [Post!]! @relation(name: "LikedPosts")。我们还提供了一个name关系来解决我们原本会创建的歧义,因为有两个关系字段针对Post该User类型。

你可以使用过滤器组合程序OR``ANDNOT创建的过滤条件的任意逻辑组合:

  • 对于要评估为“true”的AND过滤器,all嵌套条件必须为“true”。
  • 对于要评估为“true”的“OR”过滤器,至少有一个嵌套条件必须为“true”。
  • 对于要评估为“true”的NOT过滤器,所有嵌套条件都必须为“false”。

让我们先从一个简单的例子:

查询published 和其title是一个字符串的给定列表中的所有POST节点:


query {
  posts(where: {
    AND: [{
      title_in: ["My biggest Adventure", "My latest Hobbies"]
    }, {
      published: true
    }]
  }) {
    id
    title
    published
  }
}

ORANDNOT每个接受一个list作为输入,其中每个列表项是一个对象,因此需要用大括号包裹。从上述查询的样品过滤器条件包含两个滤波器对象:

  • {title_in: ["My biggest Adventure", "My latest Hobbies"]}
  • {published: true}

只有当针对POST节点这两个过滤条件符合时,该节点将被包含在响应。

你可以组合甚至嵌套过滤器组合器AND,OR并NOT创建过滤条件的任意逻辑组合。

在提供的列表中的所有POST节点查询要么published 和其title是在给定的字符串,或者有具体的id:


query {
  posts(where: {
    OR: [{
      AND: [{
        title_in: ["My biggest Adventure", "My latest Hobbies"]
      }, {
        published: true
      }]
    }, {
      id: "cixnen24p33lo0143bexvr52n"
    }]
  }) {
    id
    title
    published
  }
}

注意我们如何将AND组合嵌套在OR组合器中。

目前,标量列表过滤器JSON滤波器不可用。加入GitHub相应功能的讨论。

当查询的特定对象类型的所有节点,可以提供参数,让你进行分页查询响应。

分页允许你请求一定数量的节点。 你可以通过节点向前或向后搜索并提供可选的起始节点:

  • 从前往后查询,用first; 指定起始节点用after
  • 从后往前查询,使用last; 指定起始节点用before

你不能把firstbeforelastafter结合起来。 如果你在查询中这样做,beforeafter将被简单地忽略,只应用firstlast(在列表的开头或结尾,取决于你使用的是哪一个)。

请注意,当你只有5条数据时,你可以查询更多比如10条数据,也不会有错误消息。

你还可以通过提供skip参数跳过任意方向的任意数量的节点:

  • 当使用first时,skip会跳过列表开头的元素
  • 当使用last时,skip跳过列表末尾的元素

对于下面的例子,我们假设有三十条数据:

查询前3个节点(从前往后):


query {
  posts(first: 3) {
    id
    title
  }
}

从第6条数据开始,取5条数据(从前往后):


query {
  posts(
    first: 5
    skip: 5
  ) {
    id
    title
  }
}

查询的最后3个节点(从后往前):


query {
  posts(last: 3) {
    id
    title
  }
}

从倒数第4条数据取到倒数第10条(寻从后往前):


query {
  posts(
    last: 7
    skip: 3
  ) {
    id
    title
  }
}

查询id为cixnen24p33lo0143bexvr52n的后面3个数据:


query {
  posts(
    first: 3
    after: "cixnen24p33lo0143bexvr52n"
  ) {
    id
    title
  }
}

查询id为cixnen24p33lo0143bexvr52n的数据再跳过3条,取5个:


query {
  posts(
    first: 5
    after: "cixnen24p33lo0143bexvr52n"
    skip: 3
  ) {
    id
    title
  }
}

cixnen24p33lo0143bexvr52n当id的那条数据的前面5条:


query {
  posts(
    last: 5
    before: "cixnen24p33lo0143bexvr52n"
  ) {
    id
    title
  }
}

cixnen24p33lo0143bexvr52n当id的那条数据的前面5条数据略过,再取3个:


query {
  posts(
    last: 3
    before: "cixnen24p33lo0143bexvr52n"
    skip: 5
  ) {
    id
    title
  }
}

一个Prisma services的GraphQL API在Prisma的GraphQL schema中指定。Prisma GraphQL schema是基于数据模型自动生成的:

Prisma GraphQL schema中的Mutation类型中定义了所有的Prisma API接受的Mutation。

作为一个例子,考虑下面的数据模型:


type User {
  id: ID! @unique
  name: String!
}

这是Prisma会自动生成的Mutation:


type Mutation {
  createUser(data: UserCreateInput!): User!
  updateUser(data: UserUpdateInput!, where: UserWhereUniqueInput!): User
  deleteUser(where: UserWhereUniqueInput!): User
  upsertUser(where: UserWhereUniqueInput!, create: UserCreateInput!, update: UserUpdateInput!): User!
  updateManyUsers(data: UserUpdateInput!, where: UserWhereInput!): BatchPayload!
  deleteManyUsers(where: UserWhereInput!): BatchPayload!
}

对于你的数据模型每一种type,都形成了6个Mutation。以上述User类型作为示例,这些Mutation是:

  • createUser:创建一个新的User节点
  • updateUser:更新现有User节点
  • deleteUser:删除现有User节点
  • upsertUser:更新现有User节点; 如果它不存在,创建一个新的User节点
  • updateManyUsers:更新很多User节点
  • deleteManyUsers:一次性删除很多User节点

要详细检查你的Prisma API的所有可用的操作,你可以读取Prisma services 中的Prisma GraphQL schema。它可以用GraphQL CLI下载:


graphql get-schema --endpoint __YOUR_PRISMA_ENDPOINT__ --output prisma.graphql --no-all

了解你的Prisma API的具体能力的另一种方式是通过打开GraphQL Playground内自动生成的API文档。你可以通过点击在Playground的右边按钮SCHEMA:

本节的所有Mutation例子基于这个数据模型的Prisma services:


type Post {
  id: ID! @unique
  title: String!
  published: Boolean! @default(value: "false")
  author: User
}
type User {
  id: ID! @unique
  age: Int
  email: String! @unique
  name: String!
  posts: [Post!]!
}

Prisma API提供了三种Mutation:

  • 对象Mutation:创建,更新,更新插入或删除某[对象类型]的单个节点。
  • 嵌套Mutation:创建,更新,更新插入,删除,连接,断开连接两个或多个相关类型的多个节点。
  • 批量Mutation:更新和删除[对象类型]的许多节点。

当使用Prisma API时,下面的概念也记住有用:

  • Relation Mutation:连接和断开两个节点的关系(这是通过嵌套Mutation完成)。
  • Input types:Prisma API遵循GraphQL Mutation设计的最佳实践,并从'data`这个单个对象中接受Mutation参数。

你可以使用对象Mutation来修改特定模型的单个节点。

你可以使用createMutation创建新的节点。这些Mutation采用一个称为data的输入对象包裹所有必填字段相应类型的字段。

创建一个新的User节点:


mutation {
  createUser(
    data: {
      age: 42
      email: "alice@prisma.io"
      name: "Alice"
    }
  ) {
    id
    name
  }
}

你可以使用updateMutation改变一个节点的一个或多个字段值。要更新的节点[选择]使用where参数,经由data参数提供新的值。节点可以通过@unique指令标注的任何字段进行选择。

更改User节点的name:


mutation {
  updateUser(
    data: {
      name: "Alice"
    }
    where: {
      id: "cjcdi63j80adw0146z7r59bn5"
    }
  ) {
    id
    name
  }
}

通过其email标识更改User节点的name:


mutation {
  updateUser(
    data: {
      name: "Alice"
    }
    where: {
      email: "alice@prisma.io"
    }
  ) {
    id
    name
  }
}

当你想要么更新现有的节点,要么创建一个新的节点,你可以使用_upsert_Mutation。

根据email更新User,如果没有该User则创建一个新的User:


mutation {
  upsertUser(
    where: {
      email: "alice@prisma.io"
    }
    create: {
      email: "alice@prisma.io"
      age: 42
      name: "Alice"
    }
    update: {
      age: 42
    }
  ) {
    name
  }
}

要删除节点,需要先选择节点,在deleteMutation中使用where参数。

通过id删除User节点:


mutation {
  deleteUser(where: {
    id: "cjcdi63l20adx0146vg20j1ck"
  }) {
    id
    name
    email
  }
}

通过email删除User节点:


mutation {
  deleteUser(where: {
    email: "cjcdi63l20adx0146vg20j1ck"
  }) {
    id
    name
    email
  }
}

你可以在使用createupdateMutation的同时修改整个关系的节点。这被称为嵌套Mutation,其执行方式为[事务]

嵌套Mutation:

  • create
  • update
  • upsert
  • delete
  • connect
  • disconnect

我们提供一系列例子,罗列出所有可能出现的情况。

我们建议使用GraphQL Playground尝试不同的嵌套Mutation的行为。

你可以使用嵌套输入对象字段内的connectMutation连接到一个或多个相关的节点。

创建一个新的POST节点,并通过唯一email字段将其连接到现有的User节点:


mutation {
  createPost(data: {
    title: "This is a draft"
    author: {
      connect: {
        email: "alice@prisma.io"
      }
    }
  }) {
    id
    author {
      name
    }
  }
}

如果你在author中提供create参数,而不是connect,你会create一个新的User节点,同时新的POST节点将连接到它:


mutation {
  createPost(data: {
    title: "This is a draft"
    author: {
      create: {
        name: "Bob"
        email: "bob@prisma.io"
        age: 42
      }
    }
  }) {
    id
    author {
      name
    }
  }
}

当使用createUser而不是createPostMutation,实际上你可以同时创建并连接到多个'POST节点,因为UserPOST`有一对多关系。

创建一个新的User节点,并直接将其连接到几个新创建的POST节点:


mutation {
  createUser(
    data: {
      name: "Bob"
      email: "bob@prisma.io"
      age: 42
      posts: {
        create: [
          {
            published: true
            title: "Hello World"
          },
          {
            title: "GraphQL is great"
          }
        ]
      }
    }
  ) {
    id
    posts {
      id
    }
  }
}

创建一个新的User节点,并直接将其连接到几个新创建的和现有的POST节点:


mutation {
  createUser(
    data: {
      name: "Bob"
      email: "bob@prisma.io"
      age: 42
      posts: {
        create: [
          {
            published: true
            title: "Hello World"
          },
          {
            title: "GraphQL is great"
          }
        ]
        connect: [
          {
            id: "cjcdi63j80adw0146z7r59bn5"
          }, {
            id: "cjcdi63l80ady014658ud1u02"
          }
        ]
      }
    }
  ) {
    id
    posts {
      id
    }
  }
}

当更新的节点时,可以同时更新一个或多个关系的节点。

更新属于某一User节点的POST节点的title:


mutation {
  updateUser(
    data: {
      posts: {
        update: [
          {
            where: {
              id: "cjcf1cj0r017z014605713ym0"
            }
            data: {
              title: "Hello World"
            }
          }
        ]
      }
    }
    where: {
      id: "cjcf1cj0c017y01461c6enbfe"
    }
  ) {
    id
    posts {
      id
    }
  }
}

update接受列表数据并以wheredata字段的参数更新相关字段。

更新某个POST节点让它连接到现有User节点的name,如果没有就创建新User节点:

嵌套upserting工作方式类似:


mutation {
  updatePost(
    where: {
      id: "cjcf1cj0r017z014605713ym0"
    }
    data: {
      author: {
        upsert: {
          where: {
            id: "cjcf1cj0c017y01461c6enbfe"
          }
          update: {
            id: "cjcdi63l80ady014658ud1u02"
            name: "Alice"
          }
          create: {
            email: "alice@prisma.io"
            name: "Alice"
            age: 42
          }
        }
      }
    }
  ) {
    id
    author {
      id
    }
  }
}

User节点断开一个POST节点:


mutation {
  updateUser(
    where: {
      id: "cjcf1cj0c017y01461c6enbfe"
    }
    data: {
      posts: {
        disconnect: [
          { id: "cjcdi63l80ady014658ud1u02" }
        ]
      }
    }
  ) {
    id
    posts {
      id
    }
  }
}

当更新的节点时,你可以在同时删除一个或多个相关节点。

删除属于某User节点的POST节点:


mutation {
  updateUser(
    data: {
      posts: {
        delete: [
          {
            id: "cjcf1cj0u01800146jii8h8ch"
          },
          {
            id: "cjcf1cj0u01810146m84cnt34"
          }
        ]
      }
    }
    where: {
      id: "cjcf1cj0c017y01461c6enbfe"
    }
  ) {
    id
  }
}

当对象类型的字段具有标量列表作为其类型时,可以使用许多特殊的Mutation。

在下面的数据模型,User类型有三个这样的字段:


type User {
  id: ID! @unique
  scores: [Int!]!         # scalar list for integers
  friends: [String!]!     # scalar list for strings
  coinFlips: [Boolean!]!  # scalar list for booleans
}

当创建User的一个新的节点,可以使用set提供用于每个标量字段的值的列表。

创建一个新的User并设置scoresfriendscoinFlips值:


mutation {
  createUser(data: {
    scores: { set: [1, 2, 3] }
    friends: { set: ["Sarah", "Jane"] }
    throws: { set: [false, false] }
  }) {
    id
  }
}

当更新类型的现有节点User,可以在标量列表字段中进行许多附加操作(如scores: [Int!]!!):

  • set:用全新的列表覆盖现有的列表。
  • push(即将推出):在列表中的任意位置添加一个或多个元素。
  • pop(即将推出):删除列表开头或末尾的一个或多个元素。
  • remove(即将推出):删除列表中匹配给定过滤器的所有元素。

pushpopremove尚未实现。如果你感兴趣,你可以在这里预览

Each scalar list field takes an object with a set field in an update mutation. The value of that field is a single value or a list of the corresponding scalar type.

设置现有User节点的scores[1]:


mutation {
  updateUser(
    where: {
      id: "cjd4lfdyww0h00144zst9alur"
    }
    data: {
      scores: {
        set: 1
      }
    }
  ) {
    id
  }
}

设置现有User节点的scores[10,20,30]:


mutation {
  updateUser(
    where: {
      id: "cjd4lfdyww0h00144zst9alur"
    }
    data: {
      scores: {
        set: [10,20,30]
      }
    }
  ) {
    id
  }
}

批量Mutation可用于一次更新或删除多个节点。返回的数据只包含受影响的节点的count

注意

批量Mutation****不适用于[Subscriptions]事件!

对于许多更新的节点,你可以使用where参数选择受影响的节点,而用'data`输入新的值。所有节点都将更新为相同的值。

设置在创建于2017年的所有未发表的'POST节点published`字段为TRUE:


Mutation{
mutation {
  updateManyPosts(
    where: {
      createdAt_gte: "2017"
      createdAt_lt: "2018"
      published: false
    }
    data: {
      published: true
    }
  ) {
    count
  }
}

删除其中authornameAlice的所有未发布POST节点:


mutation {
  deleteManyPosts(
    where: {
      published: false
      author: {
        name: "Alice"
      }
    }
  ) {
    count
  }
}

一个Prisma services的GraphQL API在Prisma的GraphQL schema中指定。Prisma GraphQL schema是基于数据模型自动生成的:

Prisma GraphQL schema中的Subscriptiontype定义了所有的Prisma API接受的subscription。

作为一个例子,考虑下面的数据模型:


type User {
  id: ID! @unique
  name: String!
}

这是Prisma会生成的Subscriptiontype:


type Subscription {
  user(where: UserSubscriptionWhereInput): UserSubscriptionPayload
}

对于你的数据模型每一个类型,生成一个Subscriptions。以上述Usertype为例,此Subscriptions是:

  • user:每当创建,更新或删除User节点时触发。(除[批量Mutation]时)。

要详细检查你的Prisma API的所有可用的操作,你可以读取Prisma services Prisma的GraphQL schema。它可以用GraphQL CLI下载:


graphql get-schema --endpoint __YOUR_PRISMA_ENDPOINT__ --output prisma.graphql --no-all

了解你的Prisma API的具体能力的另一种方式是通过查看GraphQL Playground内自动生成的API文档。你可以通过点击在Playground的右边按钮链接SCHEMA:

本节的所有例子Subscriptions基于这个datamodel配置的Prisma services:


type Post {
  id: ID! @unique
  title: String!
  published: Boolean! @default(value: "false")
  author: User
}
type User {
  id: ID! @unique
  name: String!
  posts: [Post!]!
}

Prisma允许你订阅三种不同类型的事件(数据模型中的每种类型)。以Post上面数据模型中的类型为例,这些事件是:

  • 创建一个新的'Post`节点
  • 更新现有的Post节点
  • 删除现有的Post节点

注意

Subscriptions不支持[批量Mutation]

Subscription类型的对应定义如下所示(在此定义可在Prisma的GraphQL schema中找到):


type Subscription {
  post(where: PostSubscriptionWhereInput): PostSubscriptionPayload
}

下面是一个Subscriptions操作:


subscription {
  post {
    node {
      id
      title
    }
  }
}

如果没有通过where参数进一步约束,则post订阅将针对上述所有事件触发。PostSubscriptionPayload来自服务器的消息中包含哪些字段取决于事件的类型。

where参数允许用户指定监听什么事件,也许用户只希望出现某些更新的时候监听,比如:

  • ...删除一个POST
  • ...一个其中title包含特定关键字的POST创建时

这些类型的约束可以使用where参数来表示。该类型的wherePostSubscriptionWhereInput:


input PostSubscriptionWhereInput {
  # Filter for a specific mutation:
  # CREATED, UPDATED, DELETED
  mutation_in: [MutationType!]
  # Filter for a specific field being updated
  updatedFields_contains: String
  updatedFields_contains_every: [String!]
  updatedFields_contains_some: [String!]
  # Filter for concrete values of the Post being mutated
  node: PostWhereInput
  # Combine several filter conditions
  AND: [PostSubscriptionWhereInput!]
  OR: [PostSubscriptionWhereInput!]
}

上面提到的两个例子可与Prisma API中的以下Subscriptions来表示:


# Only fire for _deleted_ posts
subscription {
  post(where: {
    mutation_in: [DELETED]
  }) {
    # ... we'll talk about the selection set in a bit
  }
}
# Only fire when a post whose title contains "GraphQL" is _created_
subscription {
  post(where: {
    mutation_in: [CREATED]
    node: {
      title_contains: "GraphQL"
    }
  }) {
    # ... we'll talk about the selection set in a bit
  }
}

你现在已经很好地了解了如何订阅你感兴趣的活动。但是,你现在如何得知与事件相关的数据?

该PostSubscriptionPayload类型定义了你可以在post订阅中请求的字段。这是它的样子:


type PostSubscriptionPayload {
  mutation: MutationType!
  node: Post
  updatedFields: [String!]
  previousValues: PostPreviousValues
}

下面是根据触发Subscriptions该事件的每个字段值的概述:

mutationnodepreviousValuesupdatedFields
CREATE创建的节点nullnull
UPDATE更新节点的新值更新节点前的值更新的字段的字符串列表
DELETEnull被删除的节点null

在下文中,我们队每个字段进行更详细的讨论。

mutation字段类型是MutationTypeMutationType是一个有三个值的枚举enum类型:


enum MutationType {
  CREATED
  UPDATED
  DELETED
}

因此,PostSubscriptionPayload类型的mutation字段包含发生了什么类型的信息。

该node字段具有Post类型。它表示创建或更新的Post元素,并允许你检索有关它的更多信息。

请注意,对于DELETED-mutations,node将永远是null。如果你需要了解有关已删除Post节点的更多详细信息,可以使用该previousValues字段(稍后会详细介绍)。

updatedFields的类型为[String!]

你可能对UPDATED-mutations 感兴趣的一条信息是哪些字段已更新为Mutation。这就是该updatedFields领域的用途。

假设一个clientSubscriptions与以下SubscriptionsPrisma API:


subscription {
  post {
    updatedFields
  }
}

现在,假设服务器接收以下Mutation更新指定POSTtitle:


mutation {
  updatePost(
    where: {
      id: "..."
    }
    data: {
      title: "Prisma is the best way to build GraphQL servers"
    }
  ) {
    id
  }
}

然后,订阅的client端将收到以下Payload:


{
  "data": {
    "post": {
      "updatedFields": ["title"]
    }
  }
}

这是因为Mutation只更新了Post节点的title字段 - 没有别的。

previousValuesPostPreviousValues的类型,和POST本身看起来非常相似:


type PostPreviousValues {
  id: ID!
  title: String!
}

它基本上是一个镜像字段的辅助类型Post。

previousValues仅用于UPDATED- 和 - DELETEDMutation。对于CREATED-mutations,它将永远是null(出于同样的原因,节点null用于DELETED-mutations)。

再考虑前面示例的updatePostMutation。但是现在假设,订阅查询包括所有我们刚才讨论的字段:


subscription {
  post {
    mutation
    updatedFields
    node {
      title
    }
    previousValues {
      title
    }
  }
}

以下是服务器在执行之前的Mutation后推送到客户端的payload:


{
  "data": {
    "post": {
      "mutation": "UPDATED",
      "updatedFields": ["title"],
      "node": {
        "title": "Prisma is the best way to build GraphQL servers",
      },
      "previousValues": {
        "title": "GraphQL servers are best built with conventional ORMs",
      }
    }
  }
}

请注意,这假设更新在执行Mutation之前Post具有以下内容title:“GraphQL servers are best built with conventional ORMs”。

对于datamodel中的每个可用对象类型,将自动生成一个对象订阅。

对于给定的type,你可以订阅正在使用生成的对象正在创建的所有节点。

要订阅某种type创建的节点,则可以使用所生成的对象的Subscription和where参数指定的mutation_in:[CREATED]

订阅创建POST节点:


subscription {
  post(where: {
    mutation_in: [CREATED]
  }) {
    mutation
    node {
      description
      imageUrl
      author {
        id
      }
    }
  }
}

可以利用where对象的node参数订阅特定节点。

订阅创建特定authorPOST节点:


subscription {
  post(where: {
    AND: [
      {
        mutation_in: [CREATED]
      }, {
      node: {
        author: {
          id: "cj03x3nacox6m0119755kmcm3"
        }
      }
    ]
  }) {
    mutation
    node {
      description
      imageUrl
      author {
        id
      }
    }
  }
}

要订阅某种类型删除的节点,则可以使用所生成的对象的subscription和用where参数指定的mutation_in:[DELETED]

订阅删除POST节点:


subscription deletePost {
  post(where: {
    mutation_in: [DELETED]
  }) {
    mutation
    previousValues {
      id
    }
  }
}

可以使用where对象的node参数过滤特定节点。

订阅其中title包含特定字符串的POST节点:


subscription {
  post(where: {
    mutation_in: [DELETED]
    node: {
      title_contains: "GraphQL"
    }
  }) {
    mutation
    previousValues {
      id
    }
  }
}

要订阅某种type的更新节点,则可以使用所生成的对象的subscription和用where参数指定的mutation_in:[UPDATED]

订阅更新POST节点:


subscription {
  post(where: {
    mutation_in: [UPDATED]
  }) {
    mutation
    updatedFields
    node {
      description
      imageUrl
    }
    previousValues {
      description
      imageUrl
    }
  }
}

订阅POST节点的其中一个description字段得到更新的事件,:


subscription {
  post(where: {
    mutation_in: [UPDATED]
    updatedFields_contains: "description"
  }) {
    mutation
    node {
      description
    }
    updatedFields
    previousValues {
      description
    }
  }
}

类似于updatedFields_contains,多个过滤器的情况:

  • updatedFields_contains_every:[String!]:如果匹配指定的所有字段都进行了更新。
  • updatedFields_contains_some:[String!]:如果某些指定的字段已经更新匹配。

订阅所有POST节点的descriptionpublished字段得到更新的事件,:


subscription {
  post(where: {
    mutation_in: [UPDATED]
    updatedFields_contains_every: ["description", "published"]
  }) {
    mutation
    node {
      description
    }
    updatedFields
    previousValues {
      description
    }
  }
}

订阅其中一个POST节点的description 或者published字段得到更新的事件,:


subscription {
  post(where: {
    mutation_in: [UPDATED]
    updatedFields_contains_some: ["description", "published"]
  }) {
    mutation
    node {
      description
    }
    updatedFields
    previousValues {
      description
    }
  }
}

注意

不能同时使用updatedFields过滤器,mutation_in: [CREATED]或mutation_in: [DELETED]仅适用于UPDATE事件!

目前,关系字段Subscriptions仅可使用UPDATEDSubscriptions一种解决方法。

你可以通过“touching”节点强制进行通知。dummy: String向相关类型添加字段,并为关系状态刚刚更改的节点更新此字段。


mutation updatePost {
  updatePost(
    where: {
      id: "some-id"
    }
    data: {
      dummy: "dummy" # do a dummy change to trigger update subscription
    }
  )
}

如果你对订阅的直接关系触发感兴趣,[请加入GitHub上的讨论(https://github.com/prismagraphql/feature-requests/issues/146)。

配置docker-compose.yml文件:


version: '3'
services:
  prisma:
    image: prismagraphql/prisma:1.25
    restart: always
    ports:
    - "4466:4466"
    environment:
      PRISMA_CONFIG: |
        port: 4466
        databases:
          default:
            connector: postgres
            host: postgres
            port: 5432
            # port: 3306
            user: prisma
            password: prisma
            migrations: true
            rawAccess: true
  postgres:
    image: postgres:10.5
    restart: always
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: prisma
      POSTGRES_PASSWORD: prisma
    volumes:
      - postgres:/var/lib/postgresql/data
volumes:
  postgres:

然后就可以直接用数据库语言操作。

使用executeRaw Mutation:

创建一个新用户:


mutation {
  executeRaw(query: "INSERT INTO default$default."User" (Id, Name, "updatedAt","createdAt") VALUES ('cjnkpvm0b000d0b22j7csr04v', 'Abhi', '2018-10-22T19:54:47.606Z', '2018-10-22T19:54:47.606Z');")
}

查询所有用户:


mutation {
  executeRaw(query: "SELECT * FROM default$default."User"")
}

Prisma API通过HTTP使用。 这意味着你可以使用任何你喜欢的HTTP工具/库与Prisma API进行通信。

这里是createUserMutation的HTTP POST请求的结构:

Header

  • Authorization:携带用于验证请求的service token(前缀为'Bearer`); 仅在使用service secret部署服务时才需要。
  • Content-Type:指定请求主体(JSON)的格式,通常是application / json

Body (JSON)

  • query:要发送给API的GraphQL操作; 请注意,尽管该字段被称为“query”,它也用于 Mutation!!!
  • variables:一个JSON对象,包含在query中提交的GraphQL操作中定义的变量。

此小节所有例子都基于与下面的服务配置的Prisma services:

prisma.yml


datamodel: datamodel.prisma
secret: my-secret-42

datamodel.prisma


type User {
  id: ID! @unique
  name: String!
}

curl是一个命令行工具(除其他事项外),让你发送HTTP请求到URL。

这里是你如何发送createUserMutation使用curlPrisma API:


curl '__YOUR_PRISMA_ENDPOINT__' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer __YOUR_SERVICE_TOKEN__' \
--data-binary '{"query":"mutation ($name: String!) { createUser(data: { name: $name }) { id } }","variables":{"name":"Sarah"}}'

为了尝试这个例子,从Prisma services替换相应值__YOUR_PRISMA_ENDPOINT____YOUR_SERVICE_TOKEN__占位符,并将所得片段贴到终端。

一般来说在本地部署的服务endpoint为http://localhost:4466,使用demo server的请在yml文件中查看你的endpoint。

token请在终端输入prisma token获得,Authorization格式类似这样: Bearer sadoifjaosif……

以上请求和下面的Mutation作用相同:


mutation {
  createUser(data: {
    name: "Sarah"
  }) {
    id
  }
}

试试这个例子:

1.从Prisma services替换相应值__YOUR_PRISMA_ENDPOINT____YOUR_SERVICE_TOKEN__占位符 1.所生成的片段粘贴到你的终端,并按下回车键

fetch功能可以让你的HTTP请求从JavaScript发送到URL。

下面是你在一个node脚本中使用fetch发送createUserMutation的Prisma API:


const fetch = require('node-fetch')
const endpoint = '__YOUR_PRISMA_ENDPOINT__'
const query = `
mutation($name: String!) {
  createUser(data: {
    name: $name
  }) {
    id
  }
}
`
const variables = { name: 'Sarah' }
fetch(endpoint, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization:
      'Bearer __YOUR_SERVICE_TOKEN__',
  },
  body: JSON.stringify({ query: query, variables: variables }),
})
  .then(response => response.json())
  .then(data => console.log(JSON.stringify(data)))

同样为以下功能:


mutation {
  createUser(data: {
    name: "Sarah"
  }) {
    id
  }
}

试试这个例子:

1.从Prisma services替换相应值__YOUR_PRISMA_ENDPOINT____YOUR_SERVICE_TOKEN__占位符 1.存放在一个JavaScript文件script.js 1.通过在script.js所在的同一目录中运行yarn add node-fetch来安装node-fetch库 1.使用以下终端命令执行该脚本:node script.js

graphql-request库是fetch的轻量级封装。它主要用于需要跟一个GraphQL API交互的轻量级应用。

注意

request不支持将headers头放入请求(尚未)。因此,这个特殊的例子假定你的Prisma services部署时没有服务密码。


const { request } = require('graphql-request')
const query = `
mutation($name: String!) {
  createUser(data: {
    name: $name
  }) {
    id
  }
}
`
const variables = { name: 'Sarah' }
request('__YOUR_PRISMA_ENDPOINT__', query,  variables)
  .then(data => console.log(data))

const { GraphQLClient } = require('graphql-request')
const client = new GraphQLClient('__YOUR_PRISMA_ENDPOINT__', {
  headers: {
    Authorization: 'Bearer __YOUR_SERVICE_TOKEN__',
  },
})
const query = `
mutation($name: String!) {
  createUser(data: {
    name: $name
  }) {
    id
  }
}
`
const variables = { name: 'Sarah' }
client.request(query, variables)
  .then(data => console.log(data))

一个GraphQL Playground是一个GraphQL IDE,让你发送Query,Mutation和Subscriptions GraphQL的API。

你可以通过将终端cd到服务的prisma.yml所在的同一目录来打开Prisma API的Playground,然后运行以下命令:


prisma playground

如果prisma.yml包含secret,Playground将已经用Service token配置。你可以在窗格的左下角验证这一点,加入 HTTP header:

这意味着你可以开始将请求发送到Prisma API的时候了。Query,Mutation和Subscriptions都写在Playground的左侧窗格中。然后你点击 play - 按钮实际发送请求。结果将出现在Playground的右窗格中:

Apollo Client是在较大的前端应用中通常使用的复杂的GraphQL库。虽然所有前面的例子中使用的通用工具来发送Query和Mutation一样,Apollo Client使用用于发送Query和Mutation的专用方法:querymutation


const { ApolloClient } = require('apollo-boost')
const gql = require('graphql-tag')
const endpoint = 'https://eu1.prisma.sh/nikolas-burk/demodofin/dev'
const client = new ApolloClient({
  uri: endpoint
});
const query = gql`
  query {
    users {
      id
      name
    }
  }
`
client.query({
  query: query,
})
  .then(data => console.log(data))

const { ApolloClient } = require('apollo-boost')
const gql = require('graphql-tag')
const endpoint = 'https://eu1.prisma.sh/nikolas-burk/demodofin/dev'
const client = new ApolloClient({
  uri: endpoint
});
const mutation = gql`
  mutation($name: String!) {
    createUser(data: {
      name: $name
    }) {
      id
    }
  }
  `
const variables = { name: 'Sarah' }
client.mutate({
  mutation: mutation,
  variables: variables
})
  .then(data => console.log(data))

Prisma Bindings可以看做Prisma client替代版本。

关于GraphQL bindings 的文档here.

它和Prisma client的区别,阅读这里this forum post.

cnpm i -S prisma-binding

还是那个datamodel:


type User {
  id: ID! @unique
  name: String
}

.graphqlconfig.ymlprisma中定义:


  prisma:
    schemaPath: src/generated/prisma.graphql
    includes: [
      "prisma.graphql", 
      "seed.graphql", 
      "datamodel.graphql",
    ]
    extensions:
      prisma: prisma/prisma.yml
      codegen:
      - generator: prisma-binding
        language: typescript
        output:
          binding: src/generated/prisma.ts

部署之后修改index.ts


import { GraphQLServer } from 'graphql-yoga'
import { Prisma } from './generated/prisma-client'
import { resolvers } from './resolvers'
const prisma = new Prisma({
  endpoint: process.env.PRISMA_ENDPOINT!,
  secret: process.env.PRISMA_SECRET!,
  // debug: true,
})
 // 根据id查询某个user的名字
prisma.query.user({ where { id: 'abc' } }, '{ name }')
 // 查询所有user的id和name
prisma.query.users(null, '{ id name }')
 // 创建新user并返回她的id
prisma.mutation.createUser({ data: { name: 'Sarah' } }, '{ id }')
 // 更新一个用户的名字并返回id
prisma.mutation.updateUser({ where: { id: 'abc' }, data: { name: 'Sarah' } }, '{ id }')
 // 删除一个用户并返回该用户存在时的id
prisma.mutation.deleteUser({ where: { id: 'abc' } }, '{ id }')
const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',
  resolvers: resolvers as any,
  context: req => ({ ...req, db }),
})
server.start(({ port }) =>
  console.log('Server is running on http://localhost:${port}'),
)

在底层,每一个函数的调用都简单地转换为对你的Prisma service的实际HTTP请求(使用了graphql-request)

查询某条数据是否存在:


prisma.exists.Post({
  id: 'abc',
  author: {
    name: 'Sarah'
  }
})

更多使用方式查看GraphQL bindings 的原文档here

下一节来学习Prisma的工具和配置

Prisma CLI&配置文件