GraphQL API设计指南 GraphQL概述 GraphQL是一种用于API的查询语言,由Facebook开发。它提供了一种更高效、强大和灵活的方式来获取数据,让客户端精确指定需要的数据。 核心概念 Schema定义 定义API的类型结构和操作。 查询 客户端按需获取数据。 变更 修改数据。 GraphQL vs REST REST的限制 过度获取或获取不足 多个端点 版本管理困难 GraphQL的优势 精确获取需要的数据 单个端点 强类型系统 自描述 实现示例 使用Apollo Server(Node.js) 使用GraphQL Yoga 高级特性 分页 使用游标分页或偏移分页。 订阅 实时数据推送。 中间件 Apollo Server中间件示例。
GraphQL是一种用于API的查询语言,由Facebook开发。它提供了一种更高效、强大和灵活的方式来获取数据,让客户端精确指定需要的数据。
定义API的类型结构和操作。
type User { id: ID! name: String! email: String! posts: [Post!]! } type Post { id: ID! title: String! content: String! author: User! } type Query { user(id: ID!): User users: [User!]! post(id: ID!): Post } type Mutation { createUser(name: String!, email: String!): User! createPost(title: String!, content: String!, authorId: ID!): Post! }
客户端按需获取数据。
query GetUser { user(id: "1") { name email posts { title } } }
修改数据。
mutation CreatePost { createPost( title: "GraphQL入门" content: "这是一篇关于GraphQL的文章" authorId: "1" ) { id title } }
const { ApolloServer, gql } = require('apollo-server'); const typeDefs = gql` type User { id: ID! name: String! email: String! } type Query { user(id: ID!): User users: [User!]! } `; const resolvers = { Query: { user: (parent, args, context, info) => { return context.db.findUserById(args.id); }, users: (parent, args, context, info) => { return context.db.getAllUsers(); } } }; const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => ({ db: require('./database') }) }); server.listen().then(({ url }) => { console.log(`Server ready at ${url}`); });
const { GraphQLServer } = require('graphql-yoga'); const resolvers = { Query: { user: (parent, { id }, ctx) => { return ctx.db.user({ id }); } } }; const server = new GraphQLServer({ typeDefs: './schema.graphql', resolvers, context: req => ({ ...req, db: new Prisma() }) }); server.start(() => console.log('Server running'));
使用游标分页或偏移分页。
type Query { posts(first: Int, after: String): PostConnection! } type PostConnection { edges: [PostEdge!]! pageInfo: PageInfo! } type PostEdge { node: Post! cursor: String! } type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! startCursor: String endCursor: String }
实时数据推送。
type Subscription { postCreated: Post! } const resolvers = { Subscription: { postCreated: { subscribe: (parent, args, { pubsub }) => { return pubsub.asyncIterator(['POST_CREATED']); } } } };
Apollo Server中间件示例。
const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => { const token = req.headers.authorization || ''; const user = getUser(token); return { user }; }, plugins: [ { requestDidStart(requestContext) { console.log('Request started'); return { willSendResponse(requestContext) { console.log('Response sent'); } }; } } ] });
const resolvers = { Query: { user: async (parent, { id }, { dataSources }) => { try { return await dataSources.userAPI.getUser(id); } catch (error) { throw new ApolloError( 'Failed to fetch user', 'USER_FETCH_FAILED', { id } ); } } } };
使用DataLoader解决N+1查询问题。
const DataLoader = require('dataloader'); const userLoader = new DataLoader(async (userIds) => { const users = await db.users.findByIds(userIds); return userIds.map(id => users.find(user => user.id === id)); }); const resolvers = { Post: { author: (post, args, { userLoader }) => { return userLoader.load(post.authorId); } } };
const { AuthenticationError, ForbiddenError } = require('apollo-server'); const resolvers = { Mutation: { deletePost: async (parent, { id }, { user, dataSources }) => { if (!user) { throw new AuthenticationError('You must be logged in'); } const post = await dataSources.postAPI.getPost(id); if (post.authorId !== user.id) { throw new ForbiddenError('You are not the author'); } return dataSources.postAPI.deletePost(id); } } };
const { createComplexityLimitRule } = require('graphql-validation-complexity'); const server = new ApolloServer({ validationRules: [ createComplexityLimitRule(1000) ] });
const { ApolloServer } = require('apollo-server'); const { persistQueries } = require('@graphql-tools/persisted-queries'); const server = new ApolloServer({ persistedQueries: { ttl: 900 } });
const { RedisCache } = require('apollo-server-cache-redis'); const server = new ApolloServer({ cache: new RedisCache({ host: 'redis-server', port: 6379 }), responseCachePlugin: { sessionId: (requestContext) => requestContext.request.http.headers.get('session-id') } });
GraphQL管理和监控平台。
交互式IDE,用于测试查询。
从schema自动生成类型。
统一配置工具。
GraphQL提供了:
适合场景:
但也需要考虑:
GraphQL不是REST的替代品,而是另一种API设计选择。根据项目需求选择合适的方案。