GraphQL 对比 REST:2024 年 JavaScript 项目应选择哪种技术?

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

GraphQL vs REST:一场本应昨天就开始的决斗

\n\n

熟悉的情景:你正在用 JavaScript(或 Node.js)编写一个新项目,突然面临一个问题——前端与后端通信应该用什么?经典的 REST 还是时髦的 GraphQL?关于这个话题的争论从未停止,每个开发者都有自己的“铁打”观点。

\n\n

老实说:REST 是一个忠实可靠的老朋友,从不会让你失望。GraphQL 则是一个大胆的新手,承诺能解决你所有的问题。但如何选择?我将向你展示的不仅仅是枯燥的对比表格,而是 JavaScript 中真实的实战示例。你将看到代码是什么样的,陷阱在哪里,最重要的是——何时该用哪种技术。

\n\n

顺便说一句,如果你在用 Python 开发(别忘了这个网站是关于 Python 的),那么选择这些技术的原则非常相似。但今天我们讨论的是 JavaScript——这种在客户端和服务器端都占主导地位的语言。

\n\n

快速入门:60 秒了解 REST 和 GraphQL

\n\n

REST(表述性状态传递)

\n

这是一种架构风格,其中每个资源(用户、帖子、评论)都有其自己的 URL。你向 /api/users/1 发送 GET 请求——获取用户信息。想要他的帖子?去 /api/users/1/posts。一切简单、可预测,但……有时过于冗长。

\n\n

GraphQL

\n

这是一种查询语言和运行时环境。你只有一个端点(通常是 /graphql),并且你自己决定想要获取哪些数据。没有过度获取(返回 50 个字段,但只需要 3 个)和获取不足(需要发送 5 个请求才能拼凑出一个页面)。

\n\n

实战对比:用 JavaScript 编写代码

\n\n

让我们设想一个典型任务:需要在页面上显示用户资料及其最近的三篇帖子。我们来比较两种方法。

\n\n

基于 Express 的 REST API 示例(Node.js)

\n\n
// 基于 Express 的 REST 服务器\nconst express = require('express');\nconst app = express();\n\napp.get('/api/users/:id', (req, res) => {\n  // 返回用户的所有数据\n  const user = users.find(u => u.id === req.params.id);\n  res.json(user); // { id, name, email, phone, address, ... }\n});\n\napp.get('/api/users/:id/posts', (req, res) => {\n  // 返回用户的所有帖子\n  const posts = posts.filter(p => p.userId === req.params.id);\n  res.json(posts); // [{ id, title, body, createdAt, ... }]\n});\n\n// 客户端代码(基于 fetch 的前端)\nasync function loadProfile(userId) {\n  // 第一次请求——获取用户信息(返回很多多余数据)\n  const userResponse = await fetch(`/api/users/${userId}`);\n  const user = await userResponse.json();\n  \n  // 第二次请求——获取帖子(再次返回多余数据)\n  const postsResponse = await fetch(`/api/users/${userId}/posts`);\n  const allPosts = await postsResponse.json();\n  \n  // 只取最近 3 篇帖子\n  const latestPosts = allPosts.slice(0, 3);\n  \n  return { user, posts: latestPosts };\n}
\n\n

问题很明显:我们获取了 大量多余数据(过度获取)。如果我们只显示姓名和头像,为什么需要 email、phone、address?而帖子可能有 100 篇,我们只需要 3 篇。

\n\n

基于 Apollo Server 的 GraphQL 示例(Node.js)

\n\n
// GraphQL 模式\nconst typeDefs = `\n  type User {\n    id: ID!\n    name: String\n    avatar: String\n    posts(limit: Int): [Post]\n  }\n\n  type Post {\n    id: ID!\n    title: String\n    body: String\n  }\n\n  type Query {\n    user(id: ID!): User\n  }\n`;\n\n// 解析器(数据获取逻辑)\nconst resolvers = {\n  Query: {\n    user: (parent, { id }) => users.find(u => u.id === id),\n  },\n  User: {\n    posts: (parent, { limit }) => {\n      let result = posts.filter(p => p.userId === parent.id);\n      if (limit) result = result.slice(0, limit);\n                

博客

书籍推荐