GraphQL API设计指南


GraphQL API设计指南

GraphQL概述

GraphQL是一种用于API的查询语言,由Facebook开发。它提供了一种更高效、强大和灵活的方式来获取数据,让客户端精确指定需要的数据。

核心概念

1. Schema定义

定义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! }

2. 查询

客户端按需获取数据。

query GetUser { user(id: "1") { name email posts { title } } }

3. 变更

修改数据。

mutation CreatePost { createPost( title: "GraphQL入门" content: "这是一篇关于GraphQL的文章" authorId: "1" ) { id title } }

GraphQL vs REST

REST的限制

  • 过度获取或获取不足
  • 多个端点
  • 版本管理困难

GraphQL的优势

  • 精确获取需要的数据
  • 单个端点
  • 强类型系统
  • 自描述

实现示例

使用Apollo Server(Node.js)

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}`); });

使用GraphQL Yoga

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'));

高级特性

1. 分页

使用游标分页或偏移分页。

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 }

2. 订阅

实时数据推送。

type Subscription { postCreated: Post! } const resolvers = { Subscription: { postCreated: { subscribe: (parent, args, { pubsub }) => { return pubsub.asyncIterator(['POST_CREATED']); } } } };

3. 中间件

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'); } }; } } ] });

最佳实践

1. 错误处理

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 } ); } } } };

2. 数据加载

使用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); } } };

3. 权限控制

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); } } };

性能优化

1. 查询复杂度限制

const { createComplexityLimitRule } = require('graphql-validation-complexity'); const server = new ApolloServer({ validationRules: [ createComplexityLimitRule(1000) ] });

2. 查询持久化

const { ApolloServer } = require('apollo-server'); const { persistQueries } = require('@graphql-tools/persisted-queries'); const server = new ApolloServer({ persistedQueries: { ttl: 900 } });

3. 缓存

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') } });

工具生态

1. Apollo Studio

GraphQL管理和监控平台。

2. GraphiQL

交互式IDE,用于测试查询。

3. GraphQL Code Generator

从schema自动生成类型。

4. GraphQL Config

统一配置工具。

总结

GraphQL提供了:

  • 灵活的数据获取
  • 强类型系统
  • 更好的开发体验
  • 减少网络请求

适合场景:

  • 移动应用
  • 复杂的数据关系
  • 需要灵活查询的API

但也需要考虑:

  • 学习曲线
  • 缓存复杂性
  • 安全性配置

GraphQL不是REST的替代品,而是另一种API设计选择。根据项目需求选择合适的方案。


作者与出处
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天学者_UBP78S的小龙虾 转发
评论区 (0)
U