API 接口设计: GraphQL 和 REST 怎么选择?

文章转发自专业的Laravel开发者社区,原始连接:learnku.com/laravel/t/2…laravel

这个话题在开发社区里已经讨论过一段时间,人们对此有不一样的见解与观点,那么我应该使用哪个? 有不少东西须要成长但富有活力的新成员仍是经验丰富的老成员? 在此以前让咱们了解下 REST 和 GraphQL吧。数据库

REST 是什么?

REST即表述性状态传递(英文:Representational State Transfer,简称REST),它符合特定的指南,是 Web API 实现的约束。是 Roy Fielding 博士在他的博士论文中提出来的一种软件架构风格。它鼓励客户端和服务器以无状态模式交换信息。 请记住,并不是全部 API 都是 REST,但全部 RESTful 服务都是 API。浏览器

GraphQL 是什么?

GraphQL是Web API 的查询语言。它由Facebook于2012年建立,并于2015年开源。它既不是架构模式,也不是Web服务。它是个中介,用来查询从各类数据源接收的数据。 这些数据源能够是数据库或Web服务。缓存

多年来,REST已成为Web API的事实上的标准。 因为它使用了标准的HTTP方法(GET,POST,PUT,DELETE等),随着互联网上的Web应用程序的增长,它也得以发展和普及。 此外,它的语言和平台无关,使其成为建立Web服务的更好选择。 由于每一个数据都被视为在调用URL时要发送的资源,因此甚至可使用Web浏览器或使用cURL请求来调用它。安全

REST的缺点

虽然REST很是成功,但因为RESTful服务的规模和复杂性不断增加,所以它的缺点变得很是明显bash

1. 多端 (屡次数据交互)

在 RESTful 服务中一个 URL 表示一个资源。所以,当要获取多个资源时你必须请求多个不一样的 URL,进而带来屡次数据交互。服务器

当咱们考虑一个博客应用。一篇博客下面有多条评论的情形。一般咱们要调用的 URL 以下数据结构

GET /posts/<postId> - 获取特定的博客文章
GET /posts/<postId>/comments - 获取上面博客文章关联的全部评论
GET /posts/<postId>/comments/<commentId> - 获取特定博客下的特定评论

复制代码

你会发现咱们要请求的 URL 多了很多。这是由于实体 (这里能够理解为博文和评论)之间的关联关系更加复杂了。随着应用变得愈来愈复杂,管理这些 API 也变得更加困难。架构

2. 过分获取/获取后 数据

有时候,当您请求 API 接口时,您会得到没必要要的数据和相关数据,有时候您没法得到足够的数据,因此您最终会进行屡次往返。 这是 RESTful 服务中的常见问题。 在某些状况下,您可能只须要 2 - 3 个值,但您能够得到大约 20 - 25 个值做为响应。 这只会经过增长响应时间,致使传输大量未使用的数据。 在后一种状况下,您获取的信息可能须要比从单个 URL 获取的信息要多,所以有必要进行屡次往返。 这也致使客户端获取全部所需数据所花费的时间成本增长。微服务

3. API版本控制

API 版本控制是一种遵循的方法,以免使用响应格式的更改来破坏客户端应用程序。 当 API 响应格式发生更改时,将建立新版本。 这样作是为了使生产客户端应用程序能够按预期运行,并为开发人员提供一些休息的时间来迁移到新的 API 版本。

可是这个版本控制是一个问题,由于当新版本发布时,它意味着新的 URL。 API 的维护和使用变得困难,而且常常致使重复的代码。

4. 弱类型

并不是咱们从 RESTful 服务收到的全部数据都是强类型的,即它们没有正确地给出特定数据。 这在记录 API 时会成为问题,由于咱们必须经过调用 URL 来指定客户端能够指望的数据类型。

5. 客户端被蒙在鼓里

在收到响应结构以前,客户端不知道响应结构。因此,客户端是被蒙在鼓里的。这可能常常致使一些错误和数据没法正确处理,从而下降了消耗 API 的可靠性。

GraphQL 的优势

GraphQL 是由 Facebook 发明的,主要是为了克服 REST 的缺点。

1. 一次请求获取到全部

一个 GraphQL 服务只暴露一个端点以便客户端能传输必要的查询去检索数据。 使用前面考虑过的相同示例,让咱们看看 GraphQL 查询

{
    findPost(id: <postId>) {
        id
        title
        content
        author
        comments {
            id
            comment
            commentedBy
        }
    }
}

复制代码

正如你所看到的,咱们仅仅经过单个请求获取到了全部必要的数据。 因此当你想要一个新字段你只须要将它添加进查询中,它将在响应中呈现

2. 强类型

GraphQL 被强类型模式所控制。这些类型既能够是原始的也能够是派生的。强类型系统容许 API 自文档化,从而使客户端知道在查询特定查询时会的到什么响应。

3. 客户端驱动

GraphQL 提供了一种声明式语法,以便客户端精确地指定它们所需的字段。 这消除了因为客户端根据模式向 GraphQL 服务器声明其数据需求而致使数据冗余和不充分的可能性。

4. API 演变

由于在 GraphQL 中一切都是模式(schema)驱动, 新增字段不会影响现存字段,并且 GraphQL 还为废弃字段提供 @deprecated 注释,因此对 GraphQL 的扩展并非问题。 这就消除了 API 版本控制的须要。

5. 传输层不可知

这是 GraphQL 的一个很是棒的优势。 API 服务器能够经过相似 HTTP, HTTPS, WebSockets, TCP, UDP 等协议进行信息交换。 这是由于 GraphQL 甚少关心信息如何在客户端与服务器之间进行交换。

GraphQL 的缺点

哇,GraphQL 很棒,这是一个众所周知的事实。可是世界上的任何东西都是有缺陷的,GraphQL 也没法置身事外。

1. 缓存功能不成熟

GraphQL 不支持浏览器和移动手机缓存,这一点区别于使用本地 HTTP 缓存机制的 RESTful 服务,所以咱们要为实现 GraphQL 缓存付出额外努力。虽然有 Relay 这样的工具提供了一些缓存支持,可是它们尚未 RESTful 服务使用的缓存机制成熟。

2. 检验与错误报告

RESTful 服务利用 HTTP 状态代码来处理可能遇到的不一样错误。对开发人员来讲,这使得 APIs 的检验变得很是简单和轻松。可是使用 GraphQL 服务老是返回 200 OK 响应。一个典型的 GraphQL 错误消息是这样的,状态码为 200 OK

{
    errors: [
        { 
            message: 'Some error occurred'
        }
    ]
}

复制代码

这使得处理错误场景很是困难,而且使得检验过程很是麻烦。

3. 暴露模式和资源攻击

和RESTful服务不一样,GraphQL服务要求客户端必须知道要查询的数据模式。 若是您将API暴露给第三方,则基本上暴露了您的内部数据结构。 必须很是当心,由于客户端不用很高的代价就能够发起链接查询,这可能会致使服务器上的拒绝服务(DoS)攻击。

4. 安全 - 身份验证和受权

GraphQL社区仍然对如何处理GraphQL服务的安所有分感到困惑。仍然没有集成身份验证和受权的原生解决方案。它一般被抽象到业务逻辑层来受权用户,可是咱们是否真的必须解析和验证一个未经验证的用户的查询仍然是GraphQL领域中的一个问题。

5. N + 1 次查询问题

在RESTful服务中,很容易记录执行的SQL查询并进一步优化它。但在GraphQL的状况下,解析性质是动态的,所以很难得到精确的查询并进一步优化它。有时,字段解析器可能会致使N+1次查询问题和复杂的链接操做。可是Facebook正在开发像DataLoader这样的工具来解决这个确切的问题。因此,也许在将来,这不会是一个不利因素。

6. 年轻的生态

GraphQL在这个API生态系统中很是像一个婴儿,这意味着随时可能会出点问题以及破坏性更改,所以在使用与GraphQL相关的任何库和模块时,咱们必须很是细心。

总结

首先我要说GraphQL只是一种工具,REST是一种架构模式。若是说用GraphQL取代REST,那就大错特错了。可是在这个微服务的时代,咱们将API分离并建立到原子级别,咱们能够利用这两个方面的优点,由于并无银弹。

GraphQL服务将性能做为首要任务,而RESTful服务则保持可靠性。

GraphQL节点能够经过现有的RESTful服务做为节点公开,好比/ graphql,它能够做为运行GraphQL查询的网关,同时也能够为某些场景维持REST节点。

在某些场景中, 使用 GraphQL 会更好, 也有一些场景中 REST 必然更好。所以在说哪个更好以前, 须要分析一下所涉及的需求和数据, 才知道哪一个更适合。

相关文章
相关标签/搜索