英文:
RestController design struggle - Spring Boot REST API
问题
我是REST API开发的新手。我决定使用Spring Boot创建一个博客应用程序,但我在应用程序的设计和结构方面遇到了困难。
目前,我的应用程序包括帖子(Post)和评论(Comment)模型以及相应的存储库。对于这两个模型,我创建了服务类(PostService和CommentService)。在这些类中,我拥有所有的业务逻辑(目前只是简单的CRUD操作)。
现在,我正在考虑如何设计@RestControler以处理帖子(Posts)。在PostController中,我已经公开了以下操作:
@PostMapping("/api/posts/create")
public Post create(@RequestBody Post post) { ... }
@GetMapping("/api/posts")
public List<Post> findAll() { ... }
@GetMapping("/api/posts/{id}")
public Post findById(@PathVariable("id") Long id) { ... }
@PutMapping("/api/posts/{id}")
public Post update(@RequestBody Post post) { ... }
@DeleteMapping("/api/posts/{id}")
public void delete(@PathVariable Long id) { ... }
现在我要提出我的问题了。我想知道正确的方法是如何将评论添加到帖子中的。
- 是否应该使用CommentController类公开所有评论的CRUD方法,然后使用create方法来创建评论?
- 是否可以在PostController中添加一个新的方法
addComment
,用于创建新的评论?
在我的想法中,将评论添加到帖子中似乎应该属于帖子,但我真的不确定。
有人能给我一些关于这个问题的建议吗?
非常感谢!
再见,
Tom
英文:
I'm quite new into REST API development. I have decided to create a Blog application using Spring Boot and I'm really struggling with the design and structure of my app.
Right now my app consists of Post and Comment models and repositories. For both models, I have created service classes (PostService and CommentService). In these classes, I have all the business logic (just simple CRUD right now).
Now I am scratching my head about the design of my @RestControler for Posts. In PostController I have exposed these actions:
@PostMapping("/api/posts/create")
public Post create(@RequestBody Post post) { ... }
@GetMapping("/api/posts")
public List<Post> findAll() { ... }
@GetMapping("/api/posts/{id}")
public Post findById(@PathVariable("id") Long id) { ... }
@PutMapping("/api/posts/{id}")
public Post update(@RequestBody Post post) { ... }
@DeleteMapping("/api/posts/{id}")
public void delete(@PathVariable Long id) { ... }
Now I'm getting to my question. I am wondering what is correct design of adding a Comment to the Post.
- Should I expose all CRUD method for Comment using CommentController class and use create method?
- Is it ok to add a new method
addComment
to PostController which will create a new Comment?
In my head adding a Comment to the Post belongs to the Post, but I really don't know.
Could some of give me some advice regarding this matter?
Thanks a lot!
Bye,
Tom
答案1
得分: 1
如果我是你,我会考虑来自OpenAPI规范的REST设计原则,并遵循资源 -> 子资源 -> 方法||标识符
模式。这可能是最符合KISS原则和清晰设计的方式,以提高可读性和理解性。
@PostMapping("/api/posts/") //你不需要将/create作为单独的URI
public Post create(@RequestBody Post post) { ... }
@GetMapping("/api/posts") //这是可以的。
public List<Post> findAll() { ... }
@GetMapping("/api/posts/{id}") //可以,但{id}应该是可选的,因此你可以将此方法与上面的方法合并成一个方法。
public Post findById(@PathVariable("id") Long id) { ... }
@PutMapping("/api/posts/{id}") //可以。
public Post update(@RequestBody Post post) { ... }
@DeleteMapping("/api/posts/{id}") //可以。
public void delete(@PathVariable Long id) { ... }
现在,关于评论API设计,我会将它们包含在posts资源下,并添加以下相应的URI:
@GetMapping("/api/posts/{id}/comments/{commentId}") //commentId是可选的
@PostMapping("/api/posts/{id}/comments/") //这里不需要{commentId},只需发布有效载荷
你还可以在这里查看RESTful命名约定。
英文:
If I were you, I'd consider REST Design Principles from the OpenAPI Specification and would follow resource -> sub-resource -> method||identifier
pattern. This would probably be the most KISS and clean design for the readability and understanding purposes.
@PostMapping("/api/posts/") //you don't need /create as a separate URI
public Post create(@RequestBody Post post) { ... }
@GetMapping("/api/posts") //This is OK.
public List<Post> findAll() { ... }
@GetMapping("/api/posts/{id}") //OK, however {id} should be optional, hence you can combine this and upper methods in one method.
public Post findById(@PathVariable("id") Long id) { ... }
@PutMapping("/api/posts/{id}") //OK.
public Post update(@RequestBody Post post) { ... }
@DeleteMapping("/api/posts/{id}") //OK.
public void delete(@PathVariable Long id) { ... }
and now, for the comments API design, I would have contain them under posts resource, and would have added these corresponding URIs:
@GetMapping("/api/posts/{id}/comments/{commendId}") //commentId is optional
@PostMapping("/api/posts/{id}/comments/") //you don't need any {commendId} here, just post the payload
and etc. I hope you can come up with method signatures and other method mappings.
You can also see the RESTful naming conventions here
答案2
得分: 0
坦白说,我认为没有人能在这里给出完美的答案。这通常是一个个人决定。通常情况下,你可以关于REST API说以下几点。
-
路径应该只表示数据库中的数据结构。例如,
/api/posts
-
路径中不应包含动词。你想要做什么应该由请求类型(GET、POST、PUT、PATCH、DELETE等)处理。
现在针对你的情况。我可以很好地理解你为什么感到困惑。我认为有两种选择:
-
PostsController
你说
Comment
始终是Post
的一部分,因此你设计了这样的API。@PostMapping("/api/posts/{id}/comment") public Comment create(@PathVariable Long id, @RequestBody Comment comment) { ... }
-
CommentsController
你将
Comment
视为独立的对象,而Post
只是你通过属性添加的关系。@PostMapping("/api/comments") public Comment create(@RequestBody Comment comment) { ... }
所以这总是是一个子集 vs 创建自己的对象结构。在这种情况下,我认为我更喜欢选项2,因为我认为你可能会对这个对象执行更多操作。
此外,你可以设计你的API,使每个控制器都以将要处理的对象开头,例如/api/OBJECT/xxx/yyy
。
更新
在阅读@gulliva的评论后,我认为另一种好的方式是在CommentsController中使用这个URL @PostMapping("/api/posts/{id}/comment")
。我认为这是一个不错的方式。
英文:
To be honest I don't think that someone can give you the perfect answer here. It is often a personal decision. In common you can say the following about a REST API.
-
the path should only represent your data structure in the database. So for example
/api/posts
-
No verbs in your path. What you want to do should be handled by the RequestType (GET, POST, PUT, PATCH, DELETE, etc.)
Now to your case. I can really good understand why you are struggling. I think here are two options:
-
PostsController
You say a
Comment
is always a part of aPost
and because of this
you design your API like this.@PostMapping("/api/posts/{id}/comment") public Comment create(@PathVariable Long id), @RequestBody Comment comment) { ... }
-
CommentsController
You handle
Comment
as an own object and thePost
is just a relation you add to it by attribute.@PostMapping("/api/comments") public Comment create(@RequestBody Comment comment) { ... }
So it is always is it a Subset vs make own Object structure. I think in this case here I would prefer option 2 because I think you want do more operations on this object.
Also you can than design your API in the way that every Controller starts with the object that will be handled /api/OBJECT/xxx/yyy
UPDATE
After reading the comment from @gulliva I think also a good way is to use this URL @PostMapping("/api/posts/{id}/comment")
but put it in the CommentsController. I think this is a good way.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论