Currently I have a Spring Boot application using Spring Data REST. I have a domain entity Post
which has the @OneToMany
relationship to another domain entity, Comment
. These classes are structured as follows:
Post.java:
@Entity
public class Post {
@Id
@GeneratedValue
private long id;
private String author;
private String content;
private String title;
@OneToMany
private List<Comment> comments;
// Standard getters and setters...
}
Comment.java:
@Entity
public class Comment {
@Id
@GeneratedValue
private long id;
private String author;
private String content;
@ManyToOne
private Post post;
// Standard getters and setters...
}
Their Spring Data REST JPA repositories are basic implementations of CrudRepository
:
PostRepository.java:
public interface PostRepository extends CrudRepository<Post, Long> { }
CommentRepository.java:
public interface CommentRepository extends CrudRepository<Comment, Long> { }
The application entry point is a standard, simple Spring Boot application. Everything is configured stock.
Application.java
@Configuration
@EnableJpaRepositories
@Import(RepositoryRestMvcConfiguration.class)
@EnableAutoConfiguration
public class Application {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
}
Everything appears to work correctly. When I run the application, everything appears to work correctly. I can POST a new Post object to http://localhost:8080/posts
like so:
Body:
{"author":"testAuthor", "title":"test", "content":"hello world"}
Result at http://localhost:8080/posts/1
:
{
"author": "testAuthor",
"content": "hello world",
"title": "test",
"_links": {
"self": {
"href": "http://localhost:8080/posts/1"
},
"comments": {
"href": "http://localhost:8080/posts/1/comments"
}
}
}
However, when I perform a GET at http://localhost:8080/posts/1/comments
I get an empty object {}
returned, and if I try to POST a comment to the same URI, I get an HTTP 405 Method Not Allowed.
What is the correct way to create a Comment
resource and associate it with this Post
? I'd like to avoid POSTing directly to http://localhost:8080/comments
if possible.
Assuming you already have discovered the post URI and thus the URI of the association resource (considered to be $association_uri
in the following), it generally takes these steps:
Discover the collection resource managing comments:
curl -X GET http://localhost:8080
200 OK
{ _links : {
comments : { href : "…" },
posts : { href : "…" }
}
}
Follow the comments
link and POST
your data to the resource:
curl -X POST -H "Content-Type: application/json" $url
{ … // your payload // … }
201 Created
Location: $comment_url
Assign the comment to the post by issuing a PUT
to the association URI.
curl -X PUT -H "Content-Type: text/uri-list" $association_url
$comment_url
204 No Content
Note, that in the last step, according to the specification of text/uri-list
, you can submit multiple URIs identifying comments separated by a line break to assign multiple comments at once.
A few more notes on the general design decisions. A post/comments example is usually a great example for an aggregate, which means I'd avoid the back-reference from the Comment
to the Post
and also avoid the CommentRepository
completely. If the comments don't have a lifecycle on their own (which they usually don't in an composition-style relationship) you rather get the comments rendered inline directly and the entire process of adding and removing comments can rather be dealt with by using JSON Patch. Spring Data REST has added support for that in the latest release candidate for the upcoming version 2.2.