RESTifying Procurement – Sourcing Part 2

In this part of the procurement series I describe the minimal UBL Catalogue document subset used for RESTful sourcing. In the previous part I have already presented the minimal HTTP interaction to send a public catalogue to a client and in this posting I’ll show what information the catalogue needs to contain to enable the client to perform the next procurement step: ordering.

The intention of a catalogue is to inform the receiver what items are available and to what prices and conditions. This information is then used by the receiver when constructing an order. One way to implement this pattern would be to make the catalogue a form, let the receiver select items within the form and finally let the receiver place an order by submitting the form. However, I’ll have to take a different approach because on the one hand, there might be multiple catalogues involved in the ’shopping process’ before the ordering and on the other hand, a forms based approach is not possible when using UBL documents because they do not provide forms.

The UBL based solution is to list available items in the catalogue document and to provide SellersItemIdentification information for each item that the receiver can use to construct the order. This is essentially a client-side shopping cart pattern in which the client collects item identifiers and then submits the collected set as an order.

Here is the UBL catalogue (I did not define a schema, the intention is that the example document shows the possible elements):

GET /provider/common-catalogue
Accept: application/procurement+xml
 
200 Ok
Content-Type: application/procurement+xml
ETag: public-001
Cache-Control: public,must-revalidate
 
<?xml version='1.0' encoding='utf-8'?>
<?xml-stylesheet href='/css/catalogue.css' type='text/css'?>
<Catalog xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns="urn:oasis:names:specification:ubl:schema:xsd:Catalogue-2">
  <cbc:ID>public-001</cbc:ID>
  <cbc:IssueDate>2012-02-02</cbc:IssueDate>
  <cac:CatalogueLine>
    <cbc:ID>1</cbc:ID>
    <cac:RequiredItemLocationQuantity>
      <cac:Price>
        <cbc:PriceAmount currencyID="EUR">16.90</cbc:PriceAmount>
      </cac:Price>
    </cac:RequiredItemLocationQuantity>
    <cac:Item>
      <cbc:Name>Valve 1-54</cbc:Name>
      <cbc:Description>This valve helps with a lot of
      things</cbc:Description>
      <cac:SellersItemIdentification>
        <cbc:ID>PARTS-7615221</cbc:ID>
      </cac:SellersItemIdentification>
    </cac:Item>
  </cac:CatalogueLine>
  <cac:CatalogueLine>
    <cbc:ID>2</cbc:ID>
    <cac:RequiredItemLocationQuantity>
      <cac:Price>
        <cbc:PriceAmount currencyID="EUR">26.90</cbc:PriceAmount>
      </cac:Price>
    </cac:RequiredItemLocationQuantity>
    <cac:Item>
      <cbc:Name>Valve 2-54</cbc:Name>
      <cbc:Description>This valve helps with a lot of
      things</cbc:Description>
      <cac:SellersItemIdentification>
        <cbc:ID>PARTS-7625222</cbc:ID>
      </cac:SellersItemIdentification>
    </cac:Item>
  </cac:CatalogueLine>
  <cac:CatalogueLine>
    <cbc:ID>3</cbc:ID>
    <cac:RequiredItemLocationQuantity>
      <cac:Price>
        <cbc:PriceAmount currencyID="EUR">36.90</cbc:PriceAmount>
      </cac:Price>
    </cac:RequiredItemLocationQuantity>
    <cac:Item>
      <cbc:Name>Valve 3-54</cbc:Name>
      <cbc:Description>This valve helps with a lot of
      things</cbc:Description>
      <cac:SellersItemIdentification>
        <cbc:ID>PARTS-7635223</cbc:ID>
      </cac:SellersItemIdentification>
    </cac:Item>
  </cac:CatalogueLine>
</Catalog>

Let’s analyze that in chunks. Here is the top:

<?xml version='1.0' encoding='utf-8'?>
<?xml-stylesheet href='/css/catalogue.css' type='text/css'?>
<Catalog xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns="urn:oasis:names:specification:ubl:schema:xsd:Catalogue-2">
  <cbc:ID>public-001</cbc:ID>
  <cbc:IssueDate>2012-02-02</cbc:IssueDate>

The top of the document contains UBL-specific namespace declarations and a catalogue ID and issue date. For debugging purposes, it is useful to provide a style sheet for rendering the catalogue in a browser, so an xml-stylesheet PI is included also.

The catalogue consists of catalog lines that each contain information of one offered item:

<cac:CatalogueLine>
    <cbc:ID>3</cbc:ID>
    <cac:RequiredItemLocationQuantity>
      <cac:Price>
        <cbc:PriceAmount currencyID="EUR">36.90</cbc:PriceAmount>
      </cac:Price>
    </cac:RequiredItemLocationQuantity>
    <cac:Item>
      <cbc:Name>Valve 3-54</cbc:Name>
      <cbc:Description>This valve helps with a lot of
      things</cbc:Description>
      <cac:SellersItemIdentification>
        <cbc:ID>PARTS-7635223</cbc:ID>
      </cac:SellersItemIdentification>
    </cac:Item>
  </cac:CatalogueLine>

This example catalogue line describes the item Valve 3-54 is available at a price of EUR 36.90 and that the item is identified in the seller’s system by the ID PARTS-7635223. This seller’s item identification is what the buyer later on must use for constructing its order.

How does the client know that? This is information that needs to be covered by the media type specification. Therefore, the specification of the hypothetical media type application/procurement+xml would need to specify that catalogue documents’ catalogue lines contain seller system IDs and that these must be used in the corresponding fields of order documents.

This highlights the distinction between document schema and intended processing and why it is not enough to send the catalogue as application/xml, for example. It is exactly the hypermedia model (e.g. “take the seller’s item IDs and put them in your order later on”) that is defined by the media type and cannot be defined by a schema.

Why do I use a common media type for all UBL documents (application/procurement+xml) as opposed to one media type for each UBL document (e.g. application/ubl-catalogue+xml)?

  • A single generic media type prevents the creation of possibly many specific types; this in my experience simplifies development
  • Media types commonly identify the application that should be used to process them, so it seems consistent to think of an application that handles procurement related documents and figures out internally which specific document it has been given.
  • A type parameter can be used for content negotiation and related aspects such as declaring what format to send to certain resources. For example, in order to tell a client that an AtomPub collection accepts orders <accept>application/procurement+xml;type=Order</accept> does the job.

There is another aspect of the media type design which I will cover in one of the next parts: The primary purpose of an HTTP response is not to transfer a serialized domain object (e.g. a catalogue) but to put the client in a certain application state. Therefore, media type design must be primarily concerned with the question of what the intended application state is. The decision to make use of UBL for the procurement example series limits the design space because I cannot simply add necessary control data and/or links to UBL.

The way to solve this problem is to make use of HTTP Link headers to provide clients with information such as where to send an order once it is constructed.

Leave a Reply