Monday, January 28, 2008

Simplifying service interfaces - avoid database ids

Let's assume you have a data-centric (i.e. CRUD) service for retrieving product information. For the sake of simplicity, let's assume an XSD that looks like this:

<complexType name="product">
<sequence>
<element name="sku" type="string"/>
<element name="name" type="string"/>
<element name="description" type="string" minOccurs="0"/>
<element name="product-type" type="product-type"/>
</sequence>
</complexType>

<simpleType name="product-type">
<restriction base="string">
<enumeration value="apparel"/>
<enumeration value="subscriptions"/>
<enumeration value="digital_video"/>
</restriction>
</simpleType>


I'm defining a simple product that includes a product-type enum value, so a sample document would look like:

<product>
<sku>SHG876SHFW</sku>
<name>Navy Blue T-Shirt</name>
<description>A nice, blue shirt for your enjoyment!</description>
<product-type>apparel</product-type>
</product>

We explicitly want to keep the service interface simple and free of how things are represented within the service - meaning, not exposing database ids where they have no apparent meaning to a client of the system. Exposing the id of an entity like product seems reasonable, but is unconvincing for items such as lookup values, which in my designs have a unique integer id as well as a unique, human-readable name. The names should be immediately understandable to clients rather than needing a secondary lookup on their own end. For example, using "apparel" is much easier to understand than "4".

These lookup values I tend to treat as enum values in XML/XSD, and in the database they get their own row within a lookup table.

By asking to clients to pass in both an id and a unique name is bound for disaster - this typically happens with auto-generated code/service interfaces. So, for the simplest and easiest way to integrate, and to hide more of the internal nuts and bolts, I just use enum values in the interface.