Apollo-link-rest: 功能讨论:添加自动类型名称推断

创建于 2018-01-26  ·  22评论  ·  资料来源: apollographql/apollo-link-rest

你好,

@fbartho的 PR (#55) 将类型名添加到嵌套对象之后,我希望它能够根据对象的属性名称自动推断类型名。 然而,事实并非如此。

在 Slack 上与他交谈后,他建议我打开一个问题,以便我们可以讨论这是否可行,因为该属性很少与 TypeName 匹配。

在我的用例中,这将允许快速将 GraphQL 客户端连接到 REST 服务器,同时使用@fbartho的实现仅提供必要的自定义 __typenames。

我做了这个功能的实现,我很快就会打开一个 PR。

enhancement💡 question❔

最有用的评论

@mpgon@Rsullivan00我支持在我们的自述文件中添加一个带有链接和你的库的单行描述的#### Related Libraries部分。

所有22条评论

感谢@sky-franciscogoncalves 的贡献!! 我认为讨论这一点很重要。

我个人担心的是,在我看到的 GraphQL API 中,只有最简单的query有一个匹配的字段名,可以安全地将其 pascal-cased 放入__typename 。 他们中的许多人都有交替的共轭,而几乎所有的mutation根本不起作用。

通常,在实施typePatcher我认为人们担心拥有您可能不想要的“危险”魔法——然后需要有条件地禁用。 => 复杂性!

然而,我仍然是 GraphQL 的新手,所以如果@peggyrayzis@jbaxleyiii@sabativi能提供一些关于这个功能想法的反馈,我会很高兴的

查看我自己的 graphql API,我没有看到许多字段的 pascal 大小写与类型匹配的情况,因为我通常会这样做

type Action {
  kind: ActionKind!
  name: String!
}

注意 pascal 大小写正常工作并且不会与其他可能的类型发生冲突 我需要调用 kind -> actionKind 这感觉很奇怪,因为你已经知道你在一个动作中

type Action {
  actionKind: ActionKind!
  name: String!
}

我猜您可以将父 Schema (Action) 与嵌套字段 Pascal 大小写名称 (Kind) 连接起来,为您提供ActionKind 。 虽然这会阻止共享类型,即

type Schedule {
  start: Float
  end: Float
}
type Task {
  schedule: Schedule!
  name: String!
}
type Job {
  schedule: Schedule!
  name: String!
}

您如何看待重载现有注释以便它可以用于没有 path 属性的嵌套字段?

query MyQuery {
  action @rest(type: "Action", path: "action/") {
    id
    name
    kind @rest(type: "ActionKind") {
      name
    }
  }
}

我知道这意味着每次在查询中使用该字段时都会添加它,而不是在初始化其余链接期间一次。 然而,恕我直言,我不介意为明确性做一些额外的冗长。 此外,您已经在定义顶级架构的类型,因此必须定义子项的类型似乎更加一致。

因为 typePatcher 系统让我感觉很奇怪,因为你最终在两个非常不同的地方定义了类型,并且它把这个问题从查询中移开了太远。

@cloudkite :如果您查看这张票 #48,我们讨论了 @

也就是说, @type(…)指令可能主要是附加的,所以我不会太反对该策略的实施。 — 我的 2 美分。

试图推断某种类型永远不会适用于所有情况,因为 REST 没有标准,每个人都有自己的命名端点、资源的方式......所以我看不到光明的未来。
然而,我觉得有趣的是 @-directive 选项再次出现在桌面上,它似乎很容易设置,但人们有时可能会忘记它,所以我们需要一种方法来至少警告他们这一点。

作为个人解决方案,我正在为我公司的apollo-link-state / apollo-link-rest设置使用模式,我编写了一个工具来监视/解析这些文件,并通过代码生成我的typePatcher代码——它还调用apollo-codegen来代码生成 TypeScript 绑定。 我会在这里分享它,但它并不是一个真正友好的脚本,所以我认为它不是一个普遍适用的解决方案,但它可以满足我团队的需求。

感谢您的反馈意见。 我对 GraphQL 还是很陌生,所以很抱歉我缺乏知识。

在我看来,当前的解决方案可能会让新手感到困惑。 因为它不是很清楚 TypePatcher 是如何工作的,也不是用户应该如何使用它。

我非常喜欢@cloudkite的解决方案,因为它可以让任何阅读它们的人更好地理解查询。 如果我们继续使用此解决方案,我同意@sabativi 的意见,即我们应该让人们知道他们是否忘记对查询进行注释。

另一方面,如果我们坚持当前的解决方案,我们是否应该做同样的事情?

我也一直想知道我们是否可以从将模式绑定到 RestLink 中受益,以便我们可以从中推断出类型名。

如果我们有这样的架构:

type Schedule {
  start: Float
  end: Float
}
type Task {
  schedule: Schedule!
  name: String!
}

然后在执行查询时,我们可以验证类型Task实际上是在模式中定义的,并且嵌套对象schedule将从模式中定义的类型推断出类型名。

query MyQuery {
  task @rest(type: "Task", path: "task/") {
    name
    schedule {
      start
      end
    }
  }
}

这样的事情可以工作吗?

我真的很喜欢你应该写的所有内容都在查询中的方法,例如

query MyQuery {
  action @rest(type: "Action", path: "action/") {
    id
    name
    kind @type(name: "ActionKind") {
      name
    }
  }
}

对于新人来说更清楚。

像您建议的那样定义类型也可能会让学习 graphQL 的人感到困惑,因为这更多的是您必须在服务器端做的事情。

我喜欢这个对话

@sabativi ,感谢您的投入!

我一直在玩这个库,我仍然觉得我们应该尝试在查询中写出我们可能的一切。 但是,在某些情况下可能无法实现。

例如,如果你有一个多态嵌套对象,它的类型是从一个属性给出的,你需要有一种方法来进行复杂的操作。 因此,除非我们想出不同的解决方案,否则 TypePatcher 确实有帮助。

属性集可能会根据类型属性而改变的示例。:

{
  animals: [
    {
      type: 'cat',
      attributes: {
          ....
      },
    },
    {
      type: 'dog',
      attributes: {
          ....
      },
    },
  ],
}

在您的查询中嵌入所有内容的问题是您必须在任何地方重复自己。

示例:即使 User 对象可能嵌入在 N 个 API 中,您也必须在每个具有用户的查询中为用户的每个子部分附加类型注释。 如果你有 currentUser、buddylist、recommoteList、 nearUsers 作为查询,而 user 有地址、linkedAccounts、appData 作为子模型,那么你必须编写 4 x 3 = 12 类型注释——假设每个查询只呈现一次! 使用当前实现的 typePatcher,您只需为每个子模型修补一次。

在我看来,关于@type注释最令人讨厌的事情是,每个用户在试验查询并添加或删除键入的属性选择时都必须复制粘贴/重写注释。 这将是使用它的一个很大的摩擦点。

明确地说,我不介意我们是否添加注释——这对于非常轻量级的 REST api 注入非常有用。 — 如果您只想包装一两个小的 REST 端点。 但是,如果这是包装 API 的唯一或推荐方法,我会感到失望。 由于我们建议将链接休息作为人们将全尺寸 API 迁移到 GraphQL 的第一步,因此鼓励这种模式可能会吓跑不少人!

我完全同意你的看法。 我们应该保留这两种方法,如果可行,让它们相互作用。

我已经开始尝试一种可能的实现来允许这种行为。 但是,我不确定我是否采用了最佳方法。

目前,它能够添加每个嵌套对象的类型名和添加@type(name: "Type")注释的对象数组(数组)。

此外,如果 TypePatcher 将类型名添加到带注释的对象,它会被注释替换。 如果已经设置了 typename,我们可以通过跳过它来更改此操作。

不幸的是,我无法提供一个实现来允许添加接下来由 TypePatcher 处理的带注释的类型。 因为,如果我理解正确的话,TypePatcher 在我分析是否有任何@type注释之前会

你可以在这里查看。 我添加了测试用例来显示我之前提到的内容。

@fbartho可以使用片段解决使用相同类型的多个查询。 您只需指定一个添加所有@type(name: "Type")注释的片段,用户就可以拉入片段。

@pyros2097使用共享片段来增强@type是一个我没有考虑过的聪明主意。

  • 您将如何共享该片段以便所有查询都可以使用它?
  • 当两个指令发生冲突时会发生什么?

这就是我打算使用 apollo-link-rest 的方式。 但它失败的是深度嵌套的类型。 例如:它为 image { url } 抛出一个错误,说无法读取@type指令将解决的 'url' 的

export const UserFragment = gql`
  fragment UserFragment on User {
    id
    first_name
    last_name
    image @type(name: "Image") {
      ...ImageFragment
    }
  }
`;

export const ImageFragment = gql`
  fragment ImageFragment on Image {
    url
    width
    height
  }
`;

export const AdventureFragment = gql`
  fragment AdventureFragment on Adventure {
    id
    name
    user @type(name: "User") {
      ...UserFragment
    }
    cover_photo @type(name: "Image") {
      ...ImageFragment
    }
    created_at
    updated_at
  }
`;

export const GetUserQuery = gql`
  query UserAdventures($page: Int!) {
    user @rest(method: "GET", path: "/api/current", type: "User") {
      id @export(as: "id")
      ...UserFragment
      adventures(page: $page) @rest(method: "GET",  path: "/api/adventures", params: { id: $id }, type: "Adventure") {
        ...AdventureFragment
      }
    }
  }
  ${ImageFragment}
  ${UserFragment}
  ${AdventureFragment}
`;
  • 共享片段很容易,您只需要单独声明它们并将它们注入到您想要使用它的查询中。
  • 如果 2 个指令发生冲突,我猜最后一个指令/片段与该指令将优先。 将需要验证这一点。

@pyros2097——您将哪些 JSON 数据传递给您的回复? 你的榜样看起来不错,但它不应该尝试使用___typenameurl如果url只是一个字符串?

url 只是一个字符串,但它给了我图像片段中所有键的警告。 它还告诉我使用 apollo-inmemory-cache 中的 IntrospectionFragmentMatcher。 这可能是无法识别缓存类型且与 apollo-link-rest 无关的 apollo 内存缓存。

fragmentMatcher: By default, the InMemoryCache uses a heuristic fragment matcher.
If you are using
fragments on unions and interfaces, you will need to use an IntrospectionFragmentMatcher.
For more
information, please read [our guide to setting up fragment matching for unions & interfaces].

@sky-franciscogoncalves 请随时将您的@type()注释作为 PR 提交到此 repo,以便我们可以直接讨论它,而无需在有关“自动”类型名称推断的讨论中进一步纠结。

自 2 月以来,此线程没有任何操作,我们单独打开了 #72 以实现手动@type(name: …)指令,因此我很乐意像现在一样关闭此票证。 如果您想继续讨论真正“自动”类型名推断的技术,请重新打开——特别是如果我们能想到一种安全、标准的方法来做到这一点。 ——我认为我们的讨论没有找到那个技巧。

嗨@fbartho! 我知道这个线程已经关闭了很长时间,但之前说过,据我所知,还没有一种轻松推断类型名称的方法。 尽管@type注释非常适合进行实验,但它无法扩展。 尽管在#55 中开发的函数式类型补丁程序是一个非常好的替代方案,但我发现它对于输入大型 API 来说仍然有点过于冗长。
那样的话,我对我为轻松打补丁大型 API 而制作的库的意见非常感兴趣。 它被称为apollo-type- patcher ,这是一个盒子演示

对于找到此线程并使用符合JSON API 的服务的任何人,我已经分叉了JSON API Link以自动推断资源类型。 它还提供了一些方便的关系扁平化。

@mpgon@Rsullivan00我支持在我们的自述文件中添加一个带有链接和你的库的单行描述的#### Related Libraries部分。

此页面是否有帮助?
0 / 5 - 0 等级