如何在 Apollo GraphQL 服务器中创建嵌套解析器

25

考虑到以下Apollo Server GraphQL模式,我希望将其分解为单独的模块,因此不想在根查询架构下使用作者查询。我想将其分离。所以我添加了另一层称为authorQueries,然后将其添加到根查询中。

type Author {
    id: Int,
    firstName: String,
    lastName: String
}  
type authorQueries {
    author(firstName: String, lastName: String): Author
}

type Query {
    authorQueries: authorQueries
}

schema {
    query: Query
}

我尝试了以下操作...你可以看到在指定作者函数之前,authorQueries被添加为另一层。

Query: {
    authorQueries :{
        author (root, args) {
            return {}
       }
    }
}

当在Graphiql中进行查询时,我还添加了额外的层级..

{
    authorQueries {
        author(firstName: "Stephen") {
            id
        }
    }
}

我遇到了下面的错误。

"message": "Query.authorQueries 的解析函数未返回值。",


相关的 Apollo 文档:https://www.apollographql.com/docs/apollo-server/data/resolvers/#resolver-chains - Ezra Siton
只是想知道像这样设计 gql 是否好。authorQueiresproductQueries...等等或者按照授权的意思。我认为这不错,但很少见。 - Tokenyet
3个回答

29

要创建“嵌套”解析器,只需在父字段的返回类型上定义解析器即可。在这种情况下,您的authorQueries字段返回类型authorQueries ,因此您可以在那里放置您的解析器:

{
  Query: { authorQueries: () => ({}) },
  authorQueries: {
    author(root, args) {
      return "Hello, world!";
    }
  }
}

从技术角度而言,没有所谓的嵌套解析器——每个对象类型都有一个平坦的字段列表,并且这些字段都有返回类型。GraphQL查询的嵌套是导致结果嵌套的原因。


难道没有更好的方法,比如为作者类型定义一个解析器,它使用传递的根参数的某些值吗? 如果我这样做,每次在其他类型中使用作者时都必须创建一个解析器。 - user7776232
1
是的,在当前的GraphQL实现中,您需要为每个返回作者的字段定义一个解析器。未来可能会有所改善。 - stubailo
我很喜欢你关于GraphQL没有“嵌套”解析器的观点。在我意识到这一点之前,我曾经费尽了很多力气阅读文档。 - cafemike
1
这在深度大于1时无法工作。仅可以为查询返回的类型上的属性定义解析器,不能为这些属性上的属性定义解析器。除非我漏掉了什么,否则这是一个重大的性能问题,因为您最终会在每个请求上执行不必要的计算。 - Daniel Cooke
我已经测试过 authorQueries: () => ({}) 返回空对象的确有效。如果 TypeScript 抱怨,你可以简单地进行强制类型转换:authorQueries: () => ({} as authorQueries) - engineforce
如果authorQueries不可为空,这个方法就无法工作。而且authorQueries不可为空也是非常合理的 - 因为我们为什么要返回nullauthorQuery呢? - AMWJ

5

Query.libraries() > Library.books() > Book.author() > Author.name()

Apollo官方文档相关内容(内含一个很好的例子):

解析器链

https://www.apollographql.com/docs/apollo-server/data/resolvers/#resolver-chains

/* code from:
https://www.apollographql.com/docs/apollo-server/data/resolvers/#resolver-chains
*/

const { ApolloServer, gql } = require('apollo-server');

const libraries = [
  {
    branch: 'downtown'
  },
  {
    branch: 'riverside'
  },
];

// The branch field of a book indicates which library has it in stock
const books = [
  {
    title: 'The Awakening',
    author: 'Kate Chopin',
    branch: 'riverside'
  },
  {
    title: 'City of Glass',
    author: 'Paul Auster',
    branch: 'downtown'
  },
];

// Schema definition
const typeDefs = gql`

# A library has a branch and books
  type Library {
    branch: String!
    books: [Book!]
  }

  # A book has a title and author
  type Book {
    title: String!
    author: Author!
  }

  # An author has a name
  type Author {
    name: String!
  }

  # Queries can fetch a list of libraries
  type Query {
    libraries: [Library]
  }
`;

// Resolver map
const resolvers = {
  Query: {
    libraries() {

      // Return our hardcoded array of libraries
      return libraries;
    }
  },
  Library: {
    books(parent) {

      // Filter the hardcoded array of books to only include
      // books that are located at the correct branch
      return books.filter(book => book.branch === parent.branch);
    }
  },
  Book: {

    // The parent resolver (Library.books) returns an object with the
    // author's name in the "author" field. Return a JSON object containing
    // the name, because this field expects an object.
    author(parent) {
      return {
        name: parent.author
      };
    }
  }

  // Because Book.author returns an object with a "name" field,
  // Apollo Server's default resolver for Author.name will work.
  // We don't need to define one.
};

// Pass schema definition and resolvers to the
// ApolloServer constructor
const server = new ApolloServer({ typeDefs, resolvers });

// Launch the server
server.listen().then(({ url }) => {
  console.log(`  Server ready at ${url}`);
});

1
我发现在返回父级字段的函数中返回类型结果会绑定this参数,并破坏解析器接口,因为嵌套解析器不将父级作为第一个参数。
对于内联类型定义:
import {
  graphql,
} from 'graphql';

import {
  makeExecutableSchema, IResolverObject
} from 'graphql-tools';

const types = `
type Query {
  person: User
}

type User {
  id: ID
  name: String,
  dog(showCollar: Boolean): Dog
}

type Dog {
  name: String
}
`;

const User: IResolverObject = {
  dog(obj, args, ctx) {
    console.log('Dog Arg 1', obj);
    return {
      name: 'doggy'
    };
  }
};

const resolvers = {
  User,
  Query: {
    person(obj) {
      console.log('Person Arg 1', obj);
      return {
        id: 'foo',
        name: 'bar',
      };
    }
  }
};

const schema = makeExecutableSchema({
  typeDefs: [types],
  resolvers
});

const query = `{ 
  person {
    name,
    dog(showCollar: true) {
      name
    }
  }
 }`;


graphql(schema, query).then(result => {
  console.log(JSON.stringify(result, null, 2));
});

// Person Arg 1 undefined
// Dog Arg 1 { id: 'foo', name: 'bar' }
// {
//   "data": {
//     "person": {
//       "name": "bar",
//       "dog": {
//         "name": "doggy"
//       }
//     }
//   }
// }

您也可以使用下面的代码片段中所示的addResolveFunctionsToSchema

https://gist.github.com/blugavere/4060f4bf2f3d5b741c639977821a254f


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接