在TypeScript中GraphQL与REST:如何为你的项目做出选择

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

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

开始课程

在TypeScript中GraphQL与REST:巨头对决还是按需选择?

\n\n

当你使用TypeScript进行开发时,后端架构问题变得尤为突出。你不仅希望“能运行”,更希望类型安全、编译阶段就能捕获错误,并且代码可预测。此时,开发者面临一个永恒的选择:久经考验的REST,还是时尚灵活的GraphQL?这两种技术都能与TypeScript完美配合,但各自决定了不同的开发风格。

\n\n

在本文中,我们不会泛泛而谈或讲述基本常识。我们将通过具体示例、代码、瓶颈以及一种方案碾压另一种方案的场景,深入剖析TypeScript中的GraphQL与REST。开始吧!

\n\n

REST:值得信赖的老朋友

\n\n

REST(表述性状态转移)是一种架构风格,其中每个资源(用户、帖子、评论)都有其自己的URL。你访问/api/users/1就能获取用户信息。简单且可预测。在TypeScript项目中,REST通常通过Express、Fastify或NestJS实现。

\n\n

TypeScript中的REST类型化

\n

REST的主要痛点在于后端与前端之间缺乏强关联。你发送JSON数据,前端却要猜测:“返回了什么?”。TypeScript通过共享类型或OpenAPI(Swagger)解决了这个问题。

\n\n

示例:基于Express和TypeScript的后端

\n\n
import express, { Request, Response } from 'express';\n\ninterface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\nconst app = express();\napp.get('/api/users/:id', (req: Request, res: Response) => {\n  const user: User = { id: +req.params.id, name: 'Alice', email: 'alice@example.com' };\n  res.json(user);\n});\n
\n\n

前端(fetch):

\n\n
interface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\nasync function getUser(id: number): Promise<User> {\n  const res = await fetch(`/api/users/${id}`);\n  return res.json() as Promise<User>;\n}\n
\n\n

问题:如果后端修改了User结构,前端只能在运行时才能发现。前端的类型仅仅是副本。解决方案:从OpenAPI规范生成类型。

\n\n

TypeScript中REST的优点

\n
    \n
  • 缓存简单:HTTP缓存(CDN、浏览器)开箱即用。
  • \n
  • 结构清晰:URL = 资源,方法 = 操作(GET、POST、PUT、DELETE)。
  • \n
  • 广泛支持:任何客户端(浏览器、curl、Postman)都能理解REST。
  • \n
  • 入门门槛低:即使是新手也能在一小时内掌握。
  • \n
\n\n

REST的缺点

\n
    \n
  • 过度获取和欠获取:你要么获取了多余字段,要么需要发起多次请求。
  • \n
  • 结构僵化:要获取用户及其帖子,需要两次请求或使用变通方法(expand字段)。
  • \n
  • 类型化较弱:没有OpenAPI时,客户端的类型只是“口头承诺”。
  • \n
\n\n

GraphQL:灵活性与控制力

\n\n

GraphQL是一种查询语言,允许客户端自行决定获取哪些数据。一个端点(/graphql),一次查询——你就能精确获得所需内容。TypeScript和GraphQL是理想组合:类型可以从模式中自动生成。

\n\n

TypeScript中的GraphQL类型化

\n

首先编写模式(SDL):

\n\n
type User {\n  id: ID!\n  name: String!\n  email: String!\n  posts: [Post!]!\n}\n\ntype Post {\n  id: ID!\n  title: String!\n  content: String!\n}\n\ntype Query {\n  user(id: ID!): User\n}\n
\n\n

然后生成类型(通过graphql-codegen):

\n\n
// generated.ts\nexport type User = {\n  __typename?: 'User';\n  id: string;\n  name: string;\n  email: string;\n  posts: Array<Post>;\n};\n\nexport type Post = {\n  __typename?: 'Post';\n  id: string;\n  title: string;\n  content: string;\n};\n

                
                

博客

书籍推荐