1

I am looking for examples how nested _embedded in HAL can be programmed using Spring HATEOAS API. What are the best practices ?

Here an example of what I want to achieve:

{
    "_links": {
        "self": { "href": "/invoices" }
    },
    "_embedded": {
        "invoices": [
            {
                "_links": {
                    "self": { "href": "/invoice/1" }
                },
                "_embedded": {
                    "items": [
                        { "_links": { "self": { "href": "/product/1" }}, "id": 1, "name": "Super cheap Macbook Pro", "price": 2.99 }
                    ]
                },
                "id": 1,
                "total": 2.99,
                "no_items": 1
            },
            {
                "_links": {
                    "self": { "href": "/invoice/2" }
                },
                "_embedded": {
                    "items": [
                        { "_links": { "self": { "href": "/product/2" }}, "id": 2, "name": "Raspberry Pi", "price": 34.87 },
                        { "_links": { "self": { "href": "/product/3" }}, "id": 3, "name": "Random product", "price": 30 },
                        { "_links": { "self": { "href": "/product/4" }}, "id": 4, "name": "More randomness", "price": 30 }
                    ]
                },
                "id": 2,
                "total": 94.87,
                "no_items": 3
            }
        ]
    }
}
fellahst
  • 641
  • 1
  • 7
  • 16

1 Answers1

0

With Spring Data REST and Spring HATEOAS I see two ways to achieve kind of what you want easily.

  1. Create an Invoice and Item entity and create only a repository for the Invoice entity. That will inline the items. On the downside you are not able to query items on themselves, which is probably not what you want.
  2. Create both entities and create also repositories for both of them. Now create an Excerpt on the Invoice repository, which can be queried and has the items embedded AND the respective link collection included. But there is a downside, too: the embedded items wont have links on them. I think you should be able to include links in there by using Resource within the Projection.

See some example code using an Order with Items:

@Data
@Entity
public class Item {
  @Id
  @GeneratedValue
  private Long id;
  private String name;
}

@Data
@Entity
@Table(name = "customer_order")
public class Order {
  @Id
  @GeneratedValue
  private Long id;
  private String name;
  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
  private Collection<Item> items;
}

public interface ItemRepository extends CrudRepository<Item, Long> {
}

@RepositoryRestResource(excerptProjection = InlineItems.class)
public interface OrderRepository extends CrudRepository<Order, Long> {
}

@Projection(name = "inlineItems", types = Order.class)
public interface InlineItems {
  String getName();

  Collection<Item> getItems();
}

You can query orders like this GET http://localhost:8080/orders/1?projection=inlineItems, which will result in the following result:

{
  "name": "My Order",
  "items": [
    {
      "name": "Banana"
    },
    {
      "name": "Apple"
    }
  ],
  "_links": {
    "self": {
      "href": "http://localhost:8090/api/orders/1"
    },
    "order": {
      "href": "http://localhost:8090/api/orders/1{?projection}",
      "templated": true
    },
    "items": {
      "href": "http://localhost:8090/api/orders/1/items"
    }
  }
}
Dennis Stritzke
  • 5,198
  • 1
  • 19
  • 28