20

I have a standard Spring data JPA and Spring data Rest setup which, correctly, returns associations as links to the correct resources.

{
    "id": 1,
    "version": 2,
    "date": "2011-11-22",
    "description": "XPTO",
    "_links": {
        "self": {
            "href": "http://localhost:8000/api/domain/1"
        },
        "otherDomain": {
            "href": "http://localhost:8000/api/domain/1/otherDomain"
        }
    }
}   

However in some requests i would like to have the association to the "otherDomain" expanded (so the client does not have to do N+1 requests to get the full data).

Is it possible to configure Spring Data Rest to handle the response in this way?

Luis Santos
  • 202
  • 1
  • 2
  • 6
  • possible duplicate of [spring-data-rest, can you provide full details of entity instead of (or with) link](http://stackoverflow.com/questions/21975618/spring-data-rest-can-you-provide-full-details-of-entity-instead-of-or-with-li) – bluish Dec 09 '14 at 13:42

2 Answers2

28

The default responses will have to stay the same to make sure the payloads for PUT requests are symmetric to the ones GETs return. However, Spring Data REST introduces a feature called projections (see the JIRA ticket for details) that works as follows:

You create a dedicated interface and add all properties that you want to include in the response:

public interface MyProjection {

  String getMyProperty();

  MyRelatedObject getOtherDomain();
}

You can either

  • annotate the interface using @Projection and place it in the very same package as the domain type or a subpackage of it
  • or you manually register the projection using the RepositoryRestConfiguration and call projectionConfiguration().addProjection(…) manually (by extending RepositoryRestMvcConfiguration and overriding configureRepositoryRestConfiguration(…)).

This will cause the resources exposed for the domain type to accept a projection parameter (name also configurable ProjectionConfiguration) with the name of the projection. If given, we will skip the default rendering (which includes rendering links to related entities instead of embedding them) and let Jackson render a proxy backing the given interface.

An example of that can also be found in the Spring RESTBucks project. See the OrderProjection for the interface definition.

toong
  • 1,360
  • 12
  • 18
Oliver Drotbohm
  • 80,157
  • 18
  • 225
  • 211
  • 4
    Is it possible to expand further down the hierarchy via projections? For example if the object behind `otherDomain` itself has an association to `oneMoreDomain`, could this also be added to the original response? – muenchdo Sep 10 '14 at 10:16
  • 1
    I think if your `getOtherDomain()` method of `MyProjection` returns a projection to `oneMoreDomain` then it is possible. – Ruslan Stelmachenko Nov 09 '14 at 11:16
  • 1
    @Oliver Gierke, YOU SAVED ME SOME BACON! This really should be in official docs, I wonder why it isn't :( http://docs.spring.io/spring-data/rest/docs/2.2.1.RELEASE/reference/html/ I actually want to expand some `EAGER` associations for the default projection, but I can't seem to do that :( Do you know how? So for now, `@Projection` works... Filed https://jira.spring.io/browse/DATAREST-419 – Hendy Irawan Nov 29 '14 at 04:56
  • Oliver, I don't think the reference docs mention the same-package-or-subpackage requirement. –  Apr 08 '15 at 00:08
  • @WillieWheeler - Good catch, I created [DATAREST-508](https://jira.spring.io/browse/DATAREST-508) for that. – Oliver Drotbohm Apr 08 '15 at 16:09
  • If I need a inline object with id, how to get including id in the inlined Object? – SST Oct 17 '16 at 06:43
1

My solution applies to all requests, but some might find it relevant.

I have a simular situation, where I have the userPersons association nested in my User json response, like so:

{
"_embedded":{
  "users":[
     {
        "userName":"Albert"
        "userPersons":[
           {
              "personId":2356,
              "activeBoolean":1
           },
           {
              "personId":123617783,
              "activeBoolean":1
           }
        ],
        "_links":{
           "self":{
              "href":"http://localhost:8080/api/users/1"
           }
        }
     }
  ]

} }

My base entity like so:

@Entity
public class User {


...

@Getter @Setter
private String userName;

@Getter @Setter
@OneToMany(mappedBy = "user")
private Set<Userperson> userPersons;

}

And a single repository:

@RepositoryRestResource
public interface UserRepo extends JpaRepository<User, Integer> {
}

My solution is this:

By simply NOT exposing a Userperson @RepositoryRestResource, Spring Data Rest will embed your association.

If you define a @RepositoryRestResource for the nested type, Spring Data Rest will render a link to the resource and not embed it.

If you need the nested type repository for internal business logic, set it to @RepositoryRestResource(exported = false), to have the same behavior.

To avoid the 1+N problem, you can configure the association for eager loading, perhaps using an @EntityGraph like this guy - though I yet haven't found the best way to implement this in Spring Data Rest.

radrocket81
  • 299
  • 3
  • 10