如何使用 apollo / graphql 实现节点查询解析器

Jon*_*han 3 postgresql apollo graphql apollo-server typeorm

我正在致力于为 graphql实现一个节点接口——一个非常标准的设计模式。

寻找有关为 graphql 实现节点查询解析器的最佳方法的指导

node(id ID!): Node

我正在努力解决的主要问题是如何对类型名的 ID 进行编码/解码,以便我们可以找到要查询的正确表/集合。

目前我正在使用 postgreSQL uuid 策略和 pgcrytpo 来生成 ids。

应用程序中执行此操作的正确接缝在哪里?:

  1. 可以在数据库的主键生成中完成
  2. 可以在 graphql 接缝处完成(也许使用访问者模式

一旦选择了最好的接缝:

  1. 你如何/在哪里编码/解码?

请注意我的堆栈是:

  • Apollo客户端/服务器(来自 graphql-yoga)
  • 节点
  • 类型ORM
  • PostgreSQL

Dan*_*den 6

暴露id给客户端的(全局对象 id)不会持久化在后端——编码和解码应该由 GraphQL 服务器本身完成。这是一个基于中继如何实现的粗略示例:

import Foo from '../../models/Foo'

function encode (id, __typename) {
  return Buffer.from(`${id}:${__typename}`, 'utf8').toString('base64');
}

function decode (objectId) {
  const decoded = Buffer.from(objectId, 'base64').toString('utf8')
  const parts = decoded.split(':')
  return {
    id: parts[0],
    __typename: parts[1],
  }
}

const typeDefs = `
  type Query {
    node(id: ID!): Node
  }
  type Foo implements Node {
    id: ID!
    foo: String
  }
  interface Node {
    id: ID!
  }
`;

// Just in case model name and typename do not always match
const modelsByTypename = {
  Foo,
}

const resolvers = {
  Query: {
    node: async (root, args, context) => {
      const { __typename, id } = decode(args.id)
      const Model = modelsByTypename[__typename]
      const node = await Model.getById(id)
      return {
        ...node,
        __typename,
      };
    },
  },
  Foo: {
    id: (obj) => encode(obj.id, 'Foo')
  }
};
Run Code Online (Sandbox Code Playgroud)

注意:通过返回__typename,我们让 GraphQL 的默认resolveType行为确定接口返回的类型,因此无需为 提供解析器__resolveType

编辑:将id逻辑应用于多种类型:

function addIDResolvers (resolvers, types) {
  for (const type of types) {
    if (!resolvers[type]) {
      resolvers[type] = {}
    }
    resolvers[type].id = (obj) => encode(obj.id, type)
  }
}

addIDResolvers(resolvers, ['Foo', 'Bar', 'Qux'])
Run Code Online (Sandbox Code Playgroud)