RestBucks on .Net; querying the order

Previous posts

In my previous post; ordering coffee we end up with a response from the server with the Location of the new resource.

Then, a REST client is supposed to do a GET of this URL in order to:

  • Get some additional information, like the total cost of the order which is calculated in the backend.
  • Get the current state of the order.
  • Get the links for the next actions.

This must sound familiar if you’ve ever shop online. Even if we don’t have a graphical interface; the workflow is just like any online purchase.

In RESTBucks the order process follows this workflow:

2011-06-07_1150

Then, if we do a GET of http://restbuckson.net/order/{id} we will expect something like this:

<order>
    <links>
        <link uri="http://restbuckson.net/order/557056" 
            rel="http://restbuckson.net/docs/order-get.htm" 
            mediaType="application/vnd.restbucks+xml"/>

        <link uri="http://restbuckson.net/order/557056" 
            rel="http://restbuckson.net/docs/order-update.htm" 
            mediaType="application/vnd.restbucks+xml"/>

        <link uri="http://restbuckson.net/order/557056" 
            rel="http://restbuckson.net/docs/order-cancel.htm" 
            mediaType="application/vnd.restbucks+xml"/>

        <link uri="http://restbuckson.net/order/557056/payment" 
            rel="http://restbuckson.net/docs/order-pay.htm" 
            mediaType="application/vnd.restbucks+xml"/>
    </links>
    <location>inShop</location>
    <cost>7.60000</cost>
    <items>
        <item>
            <name>Latte</name>
            <quantity>1</quantity>
            <milk>skim</milk>
            <size>large</size>
        </item>
    </items>
    <status>unpaid</status>
</order>

This is documented here ;) . The purpose of the <links /> section is that the consumer of this API should not know much about the implementation or the location of each step. You can think this as if you were buying something in amazon, you don’t know where is the payment step and it is unlikely that some user will put an URL in the browser like “http://amazon.com/pay”.

Implementing the GET method

The implementation of the get method is this:

[WebGet(UriTemplate = "{orderId}")]
public HttpResponseMessage Get(int orderId)
{
    var order = orderRepository.GetById(orderId);

    if (order == null) return Responses.NotFound();
    
    var representation = OrderRepresentationMapper.Map(order);
    var response = new HttpResponseMessage<OrderRepresentation>(representation);
    
    return response;
}

As I said in my previous post, I am using a OrderRepresentation to -represent- the resource and serialize it.

The OrderRepresentationMapper.Map method converts an Order to an OrderRepresentation as follows:

public static class OrderRepresentationMapper
{
    public static OrderRepresentation Map(Order order)
    {
        return new OrderRepresentation
                   {
                       Cost = order.Total,
                       Status = order.Status,
                       Location = order.Location,
                       Items = order.Items.Select(i => new OrderItemRepresentation
                                    {
                                        Name = i.Product.Name,
                                        Preferences = i.Preferences.ToDictionary(p => p.Key, p => p.Value),
                                        Quantity = i.Quantity
                                    }).ToList(),
                       Links = GetLinks(order).ToList()   
                   };
        
    }

    public static IEnumerable<Link> GetLinks(Order order)
    {
        var baseUri = new UriSegment(ConfigurationManager.AppSettings["baseUri"]);
        var linker = new ResourceLinker(baseUri.Segment);

        var get = new Link(linker.GetUri<OrderResourceHandler>(r => r.Get(0, null), new { orderId = order.Id }), 
                            baseUri + "docs/order-get.htm", 
                            MediaTypes.Default);

        var update = new Link(linker.GetUri<OrderResourceHandler>(r => r.Update(0, null), new { orderId = order.Id }),
                            baseUri + "docs/order-update.htm",
                            MediaTypes.Default);

        var cancel = new Link(linker.GetUri<OrderResourceHandler>(r => r.Cancel(0), new { orderId = order.Id }),
                            baseUri + "docs/order-cancel.htm",
                            MediaTypes.Default);

        var pay = new Link(linker.GetUri<OrderResourceHandler>(r => r.Pay(0, null), new { orderId = order.Id }),
                            baseUri + "docs/order-pay.htm",
                            MediaTypes.Default);

        var receipt = new Link(linker.GetUri<OrderResourceHandler>(r => r.Receipt(0), new { orderId = order.Id }),
                            baseUri + "docs/receipt-coffee.htm",
                            MediaTypes.Default);

        switch (order.Status)
        {
            case OrderStatus.Unpaid:
                yield return get;
                yield return update;
                yield return cancel;
                yield return pay;
                break;
            case OrderStatus.Paid:
            case OrderStatus.Delivered:
                yield return get;
                break;
            case OrderStatus.Ready:
                yield return receipt;
                break;
            case OrderStatus.Canceled:
                yield break;
            default:
                yield break;
        }
    }
}

The GetLinks method builds an enumeration of the possible next steps given the status of an order. The ResourceLinker is just a fancy way to get a link to another action/resource (we didn't implement those actions yet).

If you want to explore how this work (or how to test it) you can have a look to these tests.

In the next article I am going to show how I did the Cancel operation, stay tuned!


blog comments powered by Disqus
  • Categories

  • Archives