How to consume nested objects in API resource

by Superman.Lopez   Last Updated April 16, 2019 06:05 AM

I am building my first web application, it links to the serverside through RESTfull Web API (Angular on client side, ASP.Net Core and EF Core on serverside, Automapper to map API Resources to/from domain models).
In the application I have two main models (simplified below as Delivery and Order) and each has its own API controller and endpoint (api/deliveries and api/orders). The business rules are such that: 1. an Order can be created before Delivery exists, 2. Delivery can hold an array of Order that will be included in the delivery, 3. Order can be amended after being included in Delivery.

My domain models (API resources are close to identical):

public class Delivery
{
    public int Id { get; set; }
    public Customer Customer { get; set; }
    public Address Address { get; set; }
    public DateTime EstimatedDelivery { get; set; }
    public DeliveryOrder[] Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public Product Product { get; set; }
    public int Quantity { get; set; }
}

public class DeliveryOrder
{
    public int DeliveryId { get; set; }
    public Delivery Delivery { get; set; }
    public int OrderId { get; set; }
    public Order Order { get; set; }
}

The client user interface has a view to create/amend order (instance of Order) and a view to create/amend delivery (instance of Delivery) which includes the ability to create/amend orders. As a result of the business rules, in the delivery view, I could update order individually and directly, or update delivery.orders. I am struggling to come to a suitable implementation.

Solutions I have considered:

First. In the view (Angular component) for delivery have two steps in a "save" action. In this case I need to check if order has an id or not and either put an amended order or post a new order to my api/orders. In this case my Delivery API (through Automapper profile) ignores Delivery.DeliveryOrder.Order and only compares values of Delivery.DeliveryOrder.OrderId. My client action would look similar to:

saveAction() {
    delivery.orders.forEach(o => {
        if (o.order.id) { this.httpClient.put('api/orders/' + o.order.id, o.order).subscribe( ... ); } 
        else { this.httpClient.post('api/orders/', o.order).subscribe( ... ) });
    this.httpClient.put('api/deliveries' + delivery.id, delivery).subscribe( ... );
}

Reading from other topics I understand it is not recommended to create multiple HTTP requests with a for loop to manage the number of subscriptions. Perhaps this is less of an issue if the subscriptions are combined in a forkJoin?

Second. Instead of deciding wether a specific order existed before the save action, send the whole delivery.orders to the api and let the serverside decide on whether instances of Order need to be created or amended. In that case I would patch the whole array, as discussed here. Again, my Delivery API (through Automapper profile) ignores Delivery.DeliveryOrder.Order and only compares values of Delivery.DeliveryOrder.OrderId. The saving action would look something like:

saveAction() {
    this.httpClient.patch('api/orders/' delivery.orders).subscribe(data => {
            delivery.orders = data;
            this.httpClient.put('api/deliveries' + delivery.id, delivery).subscribe( ... )
        });
}

Because this would require work on my serverside, I thought maybe it would be better to manage the whole thing on my serverside, which is the third solution I am considering.

Third: Let the server side consume Delivery.DeliveryOrder in full and do a custom mapping so that the members in Delivery.DeliveryOrder.Order are correctly amended or created. This could be done in either the Delivery controller or perhaps in a MappingProfile. The data is then simply sent through:

saveAction() {
    this.httpClient.put('api/deliveries' + delivery.id, delivery).subscribe(data => delivery = data);
}

Question(s): I have never done this and I don't feel confident about any of my solutions. Does my third solution make most sense, or should I not have Delivery API endpoint take responsibility of creating/amending the nested Order? Is there a design pattern that is considered best practice or at least more commonly used than what I have thought of?

Tags : c# asp.net web-api


Related Questions