GraphQL 例程:图书管理 API
目标
实现一个完整的图书管理 GraphQL 服务,涵盖:Schema 定义、Query(查询)、Mutation(变更)、嵌套类型(Author ↔ Book)。
完整代码
const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone');
const authors = [
{ id: '1', name: '余华' },
{ id: '2', name: '村上春树' },
];
const books = [
{ id: '1', title: '活着', authorId: '1', year: 1992 },
{ id: '2', title: '许三观卖血记', authorId: '1', year: 1995 },
{ id: '3', title: '挪威的森林', authorId: '2', year: 1987 },
];
const typeDefs = `#graphql
type Author {
id: ID!
name: String!
books: [Book!]!
}
type Book {
id: ID!
title: String!
year: Int!
author: Author!
}
type Query {
books: [Book!]!
book(id: ID!): Book
authors: [Author!]!
author(id: ID!): Author
}
type Mutation {
addBook(title: String!, authorId: ID!, year: Int!): Book!
deleteBook(id: ID!): Boolean!
}
`;
const resolvers = {
Query: {
books: () => books,
book: (_, { id }) => books.find(b => b.id === id),
authors: () => authors,
author: (_, { id }) => authors.find(a => a.id === id),
},
Book: {
author: (book) => authors.find(a => a.id === book.authorId),
},
Author: {
books: (author) => books.filter(b => b.authorId === author.id),
},
Mutation: {
addBook: (_, { title, authorId, year }) => {
const id = String(books.length + 1);
const newBook = { id, title, authorId, year };
books.push(newBook);
return newBook;
},
deleteBook: (_, { id }) => {
const idx = books.findIndex(b => b.id === id);
if (idx === -1) return false;
books.splice(idx, 1);
return true;
},
},
};
const server = new ApolloServer({ typeDefs, resolvers });
startStandaloneServer(server, { listen: { port: 4000 } }).then(({ url }) => {
console.log(`🚀 服务运行在: ${url}`);
});
测试查询
访问 http://localhost:4000 Apollo Sandbox,执行:
# 查询所有图书 + 嵌套作者信息
query {
books {
title
year
author {
name
books {
title
}
}
}
}
# 添加图书
mutation {
addBook(title: "兄弟", authorId: "1", year: 2005) {
id
title
author { name }
}
}
预期输出
{
"data": {
"books": [
{
"title": "活着",
"year": 1992,
"author": { "name": "余华", "books": [ ... ] }
},
...
]
}
}
关键点
| 概念 |
说明 |
! |
表示 Non-Null,该字段不能为 null |
[Book!]! |
列表不能为 null,列表内的元素也不能为 null |
| 嵌套 Resolver |
Book.author 独立解析,可单独优化 |
| Mutation 返回 |
返回变更后的实体(最佳实践) |