简体   繁体   English

避免在前端构建 (REST API) URL

[英]Avoiding building (REST API) URLs on the frontend

I've been working on backends for a while now and only recently started working a bit on the frontend, which got me nearer to an end-to-end REST implementation.我已经在后端工作了一段时间,直到最近才开始在前端工作,这让我更接近端到端的 REST 实现。

More to the point, an important principle of REST is to make it discoverable and consistent, so that the client will know how to deal with resources universally (HATEOAS, JsonApi etc).更重要的是,REST 的一个重要原则是使其可发现和一致,以便客户端知道如何通用地处理资源(HATEOAS、JsonApi 等)。 I've been reading this Google article and there's the following point:我一直在阅读这篇谷歌文章,有以下几点:

If an API uses HTTP simply and directly, it will only have to document three or four things.如果一个 API 简单直接地使用 HTTP,它只需要记录三到四件事。 (And if an API requires you to read a lot of documentation to learn how to use it, then it is probably not using HTTP as the uniform API.) The four elements of an HTTP API are: (如果一个 API 需要你阅读大量文档来学习如何使用它,那么它可能不是使用 HTTP 作为统一 API。)HTTP API 的四个元素是:

  1. A limited number of fixed, well-known URLs.有限数量的固定的、众所周知的 URL。 These are analogous to the names of the tables in a database.这些类似于数据库中表的名称。 For optional extra credit, make all the fixed URLs discoverable from a single one.对于可选的额外积分,可以从一个单一的 URL 中发现所有固定的 URL。

and later on....后来……

There is also a shortage of people who understand how to design good HTTP/REST APIs.也缺乏了解如何设计好的 HTTP/REST API 的人。 Unfortunately, we see many examples of APIs that attempt to adopt the entity-oriented HTTP/REST style, but fail to realize all the benefits because they do not follow the model consistently.不幸的是,我们看到许多尝试采用面向实体的 HTTP/REST 风格的 API 示例,但未能实现所有好处,因为它们没有始终如一地遵循模型。 Some common mistakes are:一些常见的错误是:

  1. Using "local identifiers" rather than URLs to encode references between entities.使用“本地标识符”而不是 URL 来编码实体之间的引用。 If an API requires a client to substitute a variable in a URI template to form the URL of a resource, it has already lost an important part of the value of HTTP's uniform interface.如果一个 API 要求客户端替换 URI 模板中的一个变量来形成资源的 URL,那么它已经失去了 HTTP 统一接口的重要价值部分。 Constructing URLs that encode queries is the only common use for URI templates that is compatible with the idea of HTTP as a uniform interface.构造对查询进行编码的 URL 是 URI 模板的唯一常见用途,它与 HTTP 作为统一接口的想法兼容。

I agree with both, but I fail to see how this can be achieved .我同意两者,但我看不出这是如何实现的

So here's the scenario:所以这是场景:

  • API endpoints: API 端点:
    • GET openapi.json / wadl / whatever-discovery-mechanism
       /articles/ /articles/$id - only for Option 2 below ... (maybe for each entity operation in case of exhaustive discovery like openapi, but I'd want to keep it minimal for now)
    • GET /articles
       { data: [ { title: "Article 1", links: { self: "/articles/1", ... } } ] }
    • GET /articles/$id
    • DELETE /articles/$id
    • ... ...
  • Frontend URLs:前端网址:
    • GET /site/articles - a page showing a list / table of articles GET /site/articles - 显示文章列表/表格的页面
    • GET /site/articles/1 - a page with a form for editing that article GET /site/articles/1 - 带有用于编辑该文章的表单的页面

When navigating to /site/articles , the frontend would know to call /articles API endpoint - which is one of the "limited fixed urls" Google mentions.当导航到/site/articles ,前端会知道调用/articles API 端点 - 这是谷歌提到的“有限的固定网址”之一。 Deleting / updating is also done given the links returned with the article entity.删除/更新也会根据文章实体返回的链接完成。 With client-side navigation, the frontend can also "redirect" to /site/articles/1 .通过客户端导航,前端还可以“重定向”到/site/articles/1

The tricky part is when a user navigates directly to /site/articles/1 - how would the page know to call /articles/$id without building the URL itself (or somehow translating it)?棘手的部分是当用户直接导航到/site/articles/1 - 页面如何知道调用/articles/$id而不构建 URL 本身(或以某种方式翻译它)?

These are the options I see:这些是我看到的选项:

  1. building the URL (this is basically "common mistake no.1" mentioned above)构建 URL(这基本上是上面提到的“常见错误一号”)
     // /site/articles/1 const apiUrl = '/articles/' + location.pathname.split('/')[3] // /articles/1
  2. building the URL from discovery links (a variation of previous option, still quite as bad IMO)从发现链接构建 URL(先前选项的变体,仍然很糟糕 IMO)
     // /site/articles/1 const apiUrl = api.endpoints.articles + location.pathname.split('/')[3] // or replace or whatever // /articles/1
  3. encoding the entity "self" link in the frontend URL对前端 URL 中的实体“self”链接进行编码
    // /site/articles/L2FydGljbGVzLzE= const apiUrl = atob(location.pathname.split('/')[3]) // /articles/1
    My concern with this is:我对此的担忧是:
    • it's kinda ugly有点丑
    • insecure (xsrf / open redirect ...)不安全(xsrf / 打开重定向...)
    • it forces the frontend to build URLs anyway (that only it understands)无论如何它都会强制前端构建 URL(只有它理解)
  4. encoding the entity identifier (which, as I take, is the "self" link) and then looking it up in /articles to then call the returned link编码实体标识符(在我看来,它是“自我”链接),然后在/articles查找它,然后调用返回的链接
    // /site/articles/L2FydGljbGVzLzE= const entityId = atob(location.pathname.split('/')[3]) const apiUrl = api.get(api.endpoints.articles) .first(article => article.links.self === entityId) .links.self // /articles/1
    • even uglier than 3. 😅比3还丑。😅
    • safe enough足够安全
    • seems pointless at first glance...乍一看似乎毫无意义......

If you are concerned that a user navigates directly to a page by typing in a URL, then that IS one of the fixed well-known URLs.如果您担心用户通过输入 URL 直接导航到某个页面,那么这就是固定的众所周知的 URL 之一。 It's likely anything that is "bookmark-able" will be in that list.任何“可添加书签”的内容都可能出现在该列表中。

the key here is the phrase "encode references between entities".这里的关键是短语“编码实体之间的引用”。 This isn't a link between entities, it is an initial entry-point, and as such it is ok to build up the URL from scratch.这不是实体之间的链接,它是一个初始入口点,因此可以从头开始构建 URL。 This is an inflexibility, but as an entry-point you have little choice.这是不灵活的,但作为切入点,您别无选择。 The "common mistake" would be embedding that "URL-building" throughout the application as you navigate relationships. “常见错误”是在您导航关系时在整个应用程序中嵌入“URL 构建”。 Ie having a list of "commenters" on an article by userid, and building those URLs up by coupling the path to users in the articles page.即,按用户 ID 列出文章上的“评论者”列表,并通过将路径耦合到文章页面中的用户来构建这些 URL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM