REST API vs GraphQL 对比

基于资源、无状态,遵循通用的 HTTP 标准

VS
GraphQL

一种查询语言——客户端精确指定自己想要的数据

8 分钟阅读Araçlar

评分对比

图表加载中…

详细评分

详细评分: REST API GraphQL ——按类别打分,满分 10 分
分类REST APIGraphQL
性能
8/10
8/10
学习难易度
9/10
6/10
生态系统
10/10
8/10
社区
10/10
8/10
就业市场
10/10
8/10
面向未来
8/10
9/10

优缺点

REST API

优点

  • 普遍易懂——每个开发者、每种语言都了解 REST
  • 可以直接使用 HTTP 缓存机制
  • 工具简单——用 curl、Postman 或浏览器就能轻松调试
  • 原生支持文件上传和二进制数据
  • 配合 CDN 缓存时性能出色
  • 无状态——每个请求相互独立,便于扩展
  • 与 webhook 和事件驱动架构兼容

缺点

  • 过度获取——端点可能返回超出需要的数据
  • 获取不足——完成一次请求可能需要调用多个端点
  • 版本管理——随着 API 演进,/v1、/v2 的维护会变得复杂
  • 移动端往往需要专用端点——可能需要引入 BFF(Backend for Frontend)模式
  • 难以将庞大的单体端点拆分成更小的部分

最适合

简单的 CRUD 操作和小规模 API公开 API 和第三方集成需要文件上传的应用希望利用 CDN 和 HTTP 缓存的系统微服务架构中的服务间通信

GraphQL

优点

  • 客户端精确指定所需字段——不会出现过度或不足获取
  • 单一端点——所有数据都通过 /graphql 流转
  • 强类型系统,带有自动生成的文档(内省)
  • 支持订阅(Subscription)实现实时数据
  • 快速迭代——前端/移动端可以在不改动后端的情况下新增字段
  • 可以在单次查询中组合多个数据源
  • 拥有 Apollo、urql 等强大的客户端库

缺点

  • HTTP 缓存困难——所有查询都是 POST 请求,内容是动态的
  • N+1 查询问题需要借助 DataLoader 之类的工具解决
  • 文件上传不如 REST 直观
  • 学习曲线——需要理解 schema、resolver、mutation、subscription 等概念
  • 对简单 API 来说可能显得过度复杂
  • 监控和日志记录不如 REST 那样直接

最适合

复杂的关系型数据模型多个客户端(Web、iOS、Android)有不同数据需求的场景需要快速迭代的产品实时功能(聊天、实时动态)消除对 BFF(Backend for Frontend)的需求

代码对比

REST API
// Swift - REST API 客户端
import Foundation

enum HTTPMethod: String {
    case GET, POST, PUT, DELETE, PATCH
}

struct APIClient {
    private let baseURL = URL(string: "https://api.example.com")!
    private let session: URLSession

    init(session: URLSession = .shared) {
        self.session = session
    }

    func request<T: Decodable>(
        path: String,
        method: HTTPMethod = .GET,
        body: Encodable? = nil
    ) async throws -> T {
        var url = baseURL.appendingPathComponent(path)
        var request = URLRequest(url: url)
        request.httpMethod = method.rawValue
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue("Bearer \(AuthManager.shared.token)", forHTTPHeaderField: "Authorization")

        if let body {
            request.httpBody = try JSONEncoder().encode(body)
        }

        let (data, response) = try await session.data(for: request)

        guard let http = response as? HTTPURLResponse else {
            throw APIError.invalidResponse
        }

        switch http.statusCode {
        case 200...299:
            return try JSONDecoder().decode(T.self, from: data)
        case 401:
            throw APIError.unauthorized
        case 404:
            throw APIError.notFound
        default:
            throw APIError.serverError(http.statusCode)
        }
    }
}

// 使用示例
let client = APIClient()
let user: User = try await client.request(path: "/users/123")
let posts: [Post] = try await client.request(path: "/users/123/posts")
GraphQL
// Swift - GraphQL Apollo 客户端
import Apollo
import Foundation

// GraphQL 查询定义(由代码生成)
// query GetUserWithPosts($id: ID!) {
//   user(id: $id) {
//     id
//     name
//     email
//     posts(limit: 5) {
//       id
//       title
//       excerpt
//       publishedAt
//     }
//   }
// }

class GraphQLService {
    private lazy var apollo = ApolloClient(url: URL(string: "https://api.example.com/graphql")!)

    func fetchUserWithPosts(id: String) async throws -> UserWithPostsQuery.Data.User {
        try await withCheckedThrowingContinuation { continuation in
            apollo.fetch(query: UserWithPostsQuery(id: id)) { result in
                switch result {
                case .success(let graphQLResult):
                    if let errors = graphQLResult.errors {
                        continuation.resume(throwing: GraphQLError(errors))
                    } else if let user = graphQLResult.data?.user {
                        continuation.resume(returning: user)
                    } else {
                        continuation.resume(throwing: APIError.notFound)
                    }
                case .failure(let error):
                    continuation.resume(throwing: error)
                }
            }
        }
    }

    func createPost(title: String, content: String) async throws -> CreatePostMutation.Data.CreatePost {
        try await withCheckedThrowingContinuation { continuation in
            apollo.perform(mutation: CreatePostMutation(title: title, content: content)) { result in
                switch result {
                case .success(let graphQLResult):
                    if let post = graphQLResult.data?.createPost {
                        continuation.resume(returning: post)
                    } else {
                        continuation.resume(throwing: APIError.invalidResponse)
                    }
                case .failure(let error):
                    continuation.resume(throwing: error)
                }
            }
        }
    }
}

结论

对于中小型 API 和公开集成,选 REST——简单、通用、缓存友好。如果有复杂的数据需求、多个客户端,并且需要快速的产品迭代,GraphQL 是个有力的选择。2025 年,许多公司采用混合方案:用 REST 承载稳定的吞吐量,用 GraphQL 处理需要灵活性的查询。

获取免费咨询
常见问题

常见问题

不会。两者服务于不同的使用场景。REST 会继续保持简单和通用;GraphQL 则是应对复杂产品需求的有力替代方案。

相关博客文章

查看全部文章

相关项目

查看全部项目
全部对比