0

I'm working on a Spring Data Rest based Spring Boot service whose data model is similar to the one in the tutorial: https://www.baeldung.com/spring-data-rest-relationships

(In defining the entities, I'm using Lombok annotations):

@Data
@NoArgsConstructor
@Entity
@Table(name = "cale")
public class Book {

    @Id
    @GeneratedValue
    private long id;

    @Column(nullable=false)
    private String title;

    @ManyToOne
    private Library library;

}


@Data
@NoArgsConstructor
@Entity
@Table(name = "library")
public class Library {


    @Id
    @GeneratedValue
    private long id;
    
    //...


}

invoking the endpoint /books I get the following json:

{
      "_embedded": {
        "books": [
          {
            "id": 22,
            "title": "The title of the book",
            "_links": {
              "self": {
                "href": "http://192.168.33.20:8080/books/22"
              },
              "book": {
                "href": "http://192.168.33.20:8080/books/22"
              },
              "library": {
                "href": "http://192.168.33.20:8080/books/22/library"
              }
            }
          },
          .
          .
          .

in HAL style, the only reference to the library linked to a given book is through an URL like http://192.168.33.20:8080/books/22/library

In order to get the id of the library associated to book 22, I have to perform a second GET call to the URL, which is inefficient in many cases.

Moreover, this makes it very hard to implement queries like "GET all books associated to the library whose id is 101".

Is there a way to let Spring Data Rest include also the id of the associated entity into the returned json? Something like:

{
      "_embedded": {
        "books": [
          {
            "id": 22,
            "title": "The title of the book",
            "library_id": 101, 
            "_links": {
            .
            .
            .
            }
          },
          .
          .
chrx
  • 2,169
  • 5
  • 24
  • 45

1 Answers1

1

You can create a projection and use it by default with an excerpt.

To define the projection :

@Projection(
  name = "customBook", 
  types = { Book.class }) 
public interface CustomBook {
 
    @Value("#{target.id}")
    long getId(); 
    
    String getTitle();
    
    @Value("#{target.getLibrary().getId()}")
    int getLibraryId();
}

And call :

http://192.168.33.20:8080/books/22?projection=customBook

To use this projection by default configure your repo :

@RepositoryRestResource(excerptProjection = CustomBook.class)
public interface BookRepository extends CrudRepository<Book, Long> {}
Fabien
  • 346
  • 2
  • 10
  • it worked, thanks! do you know if there's some way to have it working also in POST (ie. including a `"libraryId": "1010"` in the JSON body when posting a new Book)? – chrx Jun 30 '21 at 15:33
  • Did you try something like this in your POST ? : {"title": "book title","library": "http://192.168.33.20:8080:8080/library/1"} – Fabien Jun 30 '21 at 16:14
  • it works (no error and the record gets created) but in the resulting record the field library_id is set to NULL (it seems the POST just ignores the "library" property) – chrx Jul 01 '21 at 08:41
  • I also tried `"_links": { "library": { "href": "http://192.168.33.20:8080/library/101" } },`: same behaviour – chrx Jul 01 '21 at 08:45
  • Did you have a look to this question ? https://stackoverflow.com/questions/25311978/posting-a-onetomany-sub-resource-association-in-spring-data-rest?rq=1 – Fabien Jul 01 '21 at 12:33