How do I add a child object to parent using REST APIs?

user123446 :

Sorry if this question seems odd, I'm kind of new to REST APIs!

I have two entities: Order and Item.

An order can have multiple items, and an item can only have one order.

Using Spring Boot, I have set up the two entities in the corresponding relationship, and each have their own endpoint on the specified base-path which is /api.

I can add an Order or Item just fine, however, I'm trying to figure out how to add an item directly to an order.

If I create a new Order and it has the path api/orders/1, it shows that an item list is referenced in it as well at api/orders/1/items. However, if I try to POST a new item to that url, it doesn't work.

I've also tried to just create a new item at the url api/items, which works, but at this point I can't figure out how to set the Item's parent as the Order.

I'm also using Postman for this task.

Thanks for any help.

patonw :

Short answer: POST to /items using the order URL as a reference:

curl -X POST -H "Content-Type:application/json" -d '{"name": "foobar", "order": "http://localhost:8080/orders/1"}' http://localhost:8080/items

Long(-winded) answer: Colloquially, "REST" refers to a loose architectural style for providing web services over HTTP. There are a lot of best/common practices but there aren't many rules. Some of the rules that exist are commonly ignored/broken. Technically, those rules come from the original paper and some people will tell you that a service isn't RESTful if you ignore them because REST has a precise definition.

One that most people ignore in practice is HATEOAS which is the principal that a client should be able to interact with a service and discover all the endpoints without any prior knowledge using hypermedia. This is similar to how, as a human you can browse to the homepage of a site and navigate through page by page, clicking on links.

Spring Data REST provides an easy way to expose your data repositories as a hypermedia driven service. References to other entities are passed as URLs instead of plain IDs. To create an item belonging to an order, you first need the URL for the order. Then you can post to the items collection:

curl -X POST -H "Content-Type:application/json" -d '{"name": "foobar", "order": "http://localhost:8080/orders/1"}' http://localhost:8080/items

Old answer:

It's hard to say what's going wrong without seeing any of the code, but you will need to make sure the endpoint /api/order/{id}/items has a PostMapping as well as a GetMapping.

Regarding the API design, I would suggest the flatter version where you create items by POSTing to /api/items with the order id in the body over /api/orders/1/items. This more closely aligns with database normalization and it makes it clearer which controller should handle which requests.

The order table shouldn't store any item ids. The item entries store their order ids. To get the list of items in an order, filter all the items by the order id.

POST /api/items
{
  "orderId": 123,
  "skuId": 234,
  "price": 42.10,
  "gift": false
}

vs

POST /api/orders/123/items
{
  "skuId": 234,
  "price": 42.10,
  "gift": false
}

In your ItemController you can have something like

@PostMapping
public Item createItem(@RequestBody ItemRequestDTO) {
...
}

Where ItemRequestDTO is another class with only the fields needed to create an item, including the order ID.

P.S. I'm guessing at some point you'll use a database for persistence in which case you can use @ManyToOne and @OneToMany mappings.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=161899&siteId=1
Recommended