【问题标题】:restful-like CRUD operation url pattern for nested model嵌套模型的类 CRUD 操作 url 模式
【发布时间】:2012-08-31 02:21:52
【问题描述】:

一般来说,model的CRUD操作url模式可以是这样的(假设Model是Post):

new: /posts/new(get)
create:/posts/(post)
edit:/posts/edit(get)
update:/posts/1(put)
get:/posts/1(get)

但是如果有嵌套模型“评论”。

并且“帖子”和“评论”的关联是一对多的。

那么对于 cmets 来说,CURD 操作 url 模式应该是什么样的呢?

new: /posts/1/comments/new   or /comments/new
create:?
edit:?
update:?
.......

最佳做法是什么?


更新:

评论的url好像应该是这样的:

Get one comment for one post: /posts/1/comments/1

create: /posts/1/comments

update: /posts/1/comments/1

delete: /posts/1/comments/1

现在我对更新和删除操作感到困惑。

更新和删除:/posts/1/comments/1

既然指定了评论id,请问url里面的/posts/1是不是必须的?

【问题讨论】:

  • 你最后做了什么?

标签: http rest webserver associations restful-url


【解决方案1】:

我认为关键是评论是否被帖子资源“包含”。请记住,RESTful url 应该是永久链接,因此在所有场景下,特定评论的终点不得更改。听起来它已包含在内,因此 url 模式可以将评论嵌套在帖子中。如果不是这种情况(例如,评论可能会移动到另一个帖子,如果嵌套会更改网址),那么您需要一个更扁平的结构,其中包含帖子资源引用的 /comment/{id} 网址)。

关键是如果它是一个 RESTful “超媒体 API”,那么它就像网络一样,它会不断链接到嵌套或引用的资源。它不依赖于客户端必须理解 REST 模式或关于什么端点保存引用或包含的特殊知识 资源。

http://blog.steveklabnik.com/posts/2012-02-23-rest-is-over

如果“评论”是“帖子”资源下的资源:

([httpVerb] /url)

得到一个帖子:

[get] /posts/{id}
body has a couple options - either it contains the full deep comments array
(depends on how much data, chat pattern)
{
    id:xxx,
    title:my post,
    comments: [...]
}

... or it just contains the post resource with a url reference to the comments e.g.
{
   id: xxx,
   title: my post,
   commentsUrl: /posts/xxx/comments
}

could also have an option like this (or other options to control depth):
[get] /posts/{id}?deep=true

获取帖子中的 cmets 集合:

[get] /posts/{id}/comments
returns 200 and an array of comments in the response body

为帖子创建评论:

[post] /posts/{id}/comments
body contains json object to create
returns a 201 created

在帖子下编辑评论:

[patch|post] /posts/{id}/comments/{id}
body contains json object with subset of fields/data to update
returns a 200

替换帖子:

[put] /posts/{id}/comment/{id}
body contains json object to *replace*
returns a 200

如果每个帖子有大量 cmets,您还可以考虑分页模式:

{
    id: xxx,
    title: myPost,
    pages:6,
    commentsUrl:/posts/xxx/comments/page/1
}

然后:

/posts/{id}/comments/pages/{pageNo}

{
    nextPage: /posts/xxx/comments/2,
    pages:7,
    comments:
    [ { ...,...,}]
}

每个页面都会引用下一页、页面计数和该页面的 cmets 数组。如果您使用分页模式,那么数组中的每个评论都会有一个指向单个评论的引用 url。

如果您发现自己在 url 中添加了一个操作,那么您可能做错了什么。好读:http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http

【讨论】:

  • 非常感谢您的回复,但我还有一个问题,您可以查看我的更新吗? :)
  • 如果评论 ID 是唯一的,无论帖子如何,您都可以在技术上执行 /cmets/1。但我会(1)在动词的模式上保持一致,(2)回到帖子是否“包含”评论(永远不能移动)。此外,如果您使用 /post/{id}/comment/{id},则评论 ID 可能仅在该帖子中是唯一的(例如 /post/1/comment/1 和 /post/2/comment/1)
  • 仅在帖子中?如何实施?现在我在 mysql 中有表格帖子和评论,并且每个人都拥有唯一的 id
  • 如果您在帖子中增加,您将不得不编写 sql 代码来执行此操作。好处是 url 是一个易于使用的 url(您几乎可以猜到下一个 url 应该是什么) - 缺点是您必须编写一些代码来生成公共 id。但是,如果评论在逻辑上包含在帖子中,则仍然可以选择仅利用 sql 生成的唯一 id 并保留 /post/{id}/comment/{id} 。它确实让内部存储细节泄漏 - 取决于你想要的“纯粹”程度:)
【解决方案2】:

您希望使用规范 URL 进行删除/更新,这将是完整的。更重要的是,您不应该将来自数据库的主键值公开为公共 api 中的 id,这是您的宁静 URL 空间。这些值将来可能会根据数据库更新、从备份还原或其他任何事情发生变化,具体取决于供应商。如果您能提供帮助,您不希望基础架构更改使您的所有 URL 都无效。

如果您使用/posts/{postnum}/comments/{commentnum},您可以为每个帖子从 1 开始为 public 评论 id 编号,从而获得更短、更好的 URL。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-10
    • 1970-01-01
    相关资源
    最近更新 更多