掘金 后端 ( ) • 2024-04-05 18:30

安装依赖npm install @apollo/server graphql

示例代码

通过Apollo server官网的示例了解graphql:稍微改了改

import { ApolloServer } from '@apollo/server'; 
import { startStandaloneServer } from '@apollo/server/standalone'; 

```javascript
// #定义需要获取的数据 正常resolvers解析器获取在数据库中的数据 
const books = [
  {
    title: "The Awakening",
    author: "Kate Chopin",
  },
  {
    title: "City of Glass",
    author: "Paul Auster",
  },
];
// #定义一个graphql的模式(Schema):可以当作一个数据查询规范

const typeDefs = `#graphql 
  # 默认值 将query字段映射到Query 所以在前端可以使用query查询而不是使用Query (解释前端为什么是小写q)
  schema {
   query: Query
  }
  #定义了一个 Book 类型
  type Book {
    title: String
    author: String
  } 
  #定义了一个查询字段 这里下边会解释
  type Query { 
    books: [Book] 
    book(title: String!): Book
  } `;
 //定义一个解析器
const resolvers = {
  Query: {
    books: () => books,
    // 解析器函数参数 parent, args->传入查询的参数, context, info
    book: (_, { title }) => books.find(book => book.title === title),
  },
};
//通过ApolloServer创建一个graphql服务 
const server = new ApolloServer({
  typeDefs,
  resolvers,
});
//启动服务 
startStandaloneServer(server, {
  listen: { port: 9000 },
}).then(({ url }) => {
  console.log(`🚀  Server ready at: ${url}`);
});
console.log(`🚀  Server ready at: ${url}`);
//查询字段 前端  
`query { book(title: "The Awakening") { author } }`

通过代码不难理解:首先创建了一个 Book 类型,然后就是Query类型,这在graphql中是一个特殊类型;

type Query { books: [Book] }

这里我们定义了books: [Book]

books是前端使用的查询字段,查询结果是Book类型数组。

同时也指定了对应的解析器函数的名称为books,返回值是一个Book类型数组;

book(title: String!): Book

查询字段为book 参数为title string类型;解析器函数名称:book 函数参数为title string类型 返回结果为Book类型

运行示例代码

node filename 访问:http://localhost:4000/

此时会直接打开apollo server的沙箱,尝试不同的query,查看返回结果;

1712305392015.jpg

解析器函数参数

涉及到所有四个参数:parent, args, context, 和 info

示例场景

假设我们有一个GraphQL API,用于管理图书和作者。我们将创建一个查询解析器,用于根据书籍ID获取书籍信息,同时这本书会引用其作者的信息。

模式(Schema)

首先,我们定义GraphQL模式:

graphqlCopy code
type Book {
  id: ID!
  title: String
  author: Author
}

type Author {
  id: ID!
  name: String
}

type Query {
  book(id: ID!): Book
}

解析器

现在,我们来定义解析器函数。这个解析器将演示如何使用所有四个参数。

const resolvers = {
  Query: {
    // 解析器函数
    book: (parent, args, context, info) => {
      // 从args中提取id
      const { id } = args;

      // 假设从数据库或其他数据源中获取书籍信息
      const book = database.books.find(book => book.id === id);

      // 使用context来访问共享资源,比如用户信息或数据库
      const user = context.user;

      // 使用info进行高级操作,比如字段选择
      const fieldName = info.fieldName;

      // 返回找到的书籍
      return book;
    }
  },

  Book: {
    // 为Book类型的author字段提供解析器
    author: (parent, args, context, info) => {
      // 使用parent参数,它是上一个解析器(这里是book)的返回值
      const authorId = parent.authorId;
      return database.authors.find(author => author.id === authorId);
    }
  }
};

参数解释

  1. parent/root:

    • book解析器中,parent是顶级类型(Query),通常不被使用。
    • author解析器中,parentbook解析器的返回值,即一本书的信息。
  2. args:

    • 包含了传入查询的参数,如book解析器中的id
  3. context:

    • 一个跨所有解析器共享的对象,常用于存储认证信息、数据库连接等。
    • 在示例中,可以用来访问当前用户信息(context.user)。
  4. info:

    • 包含了查询的特定信息,如字段名称(info.fieldName)。
    • 这在复杂的查询和优化中特别有用。

总结

在这个示例中,我们展示了GraphQL解析器如何处理更复杂的逻辑,同时演示了如何使用所有四个参数。这种灵活性允许开发者根据具体场景来实现复杂的数据获取和转换逻辑。