ALPHA - This content is a work in progress and is published for community feedback. This page is a wiki, please provide your feedback in the comments below.

Applies To

  • Microsoft .NET, 3.5 SP1 and up
  • Windows Server 2003, 2008

Scenario

In this scenario you are building an SOA and you have made the decision to use REST as the architecture to expose the endpoints for your services. You also have control of you data-model and good access to business experts and so have made the decision to use a rich domain model for your business logic.

Scope

Since REST and domain modeling are both complex fields, with their own best practice guidance, we consider much of this guidance is out of scope for this document. Please see the additional references at the end of the document for a list of recommended resources.

Key Characteristics

  • REpresentational State Transfer (REST) based web service layer.
  • A domain model is used to model the business area you are working in.
  • Resource handlers and domain (business) logic are located on the same physical machine.
  • Automated clients and user interfaces can be written on top of the REST service layer.
  • Clients can directly communicate with the REST service layer or can use a custom library which hides all HTTP related work.
  • The application has full autonomy over the domain model and the database schema.

Applicability

REST does not in any way define how you structure your business logic and a domain model says very little about how you provide distributed access to the behavior it provides. It is thus important to think about the applicability of these two techniques to your problem separately.

REST

REST is an architectural style and it is thus important that you carefully make the decision about whether to use it. In particular whilst REST's synchronous request-response model can be used to build scalable systems other options exist including messaging and Web Services.

It is also quite possible that REST might be used in some parts of a system whilst messaging makes sense in other places.

Domain Model

Although we use a domain model we do not predicate how this domain model should be structured. In particular whilst some DDD patterns are used we do not believe DDD is applicable in all situations, in particular DDD requires several factors including a team experienced with analysis/design and consistent access to domain experts (proxies within the development team do not count).

Furthermore there is no reason that the REST elements of this architecture cannot be used just as happily over an anemic domain model, or over a model designed by the IT team to meet technical considerations. In fact if you are lacking a DDD pre-requisite, such as access to domain experts, then you should consider using a simple model instead of going straight to DDD.

Another benefit of this style is that the domain model is entirely encapsulated and is customized to the task at hand. Thus within the boundaries of an application (or large business service) you can make the most informed choice without this decision spilling out.

Terminology

REST

  • Representation – “Any useful information about the state of a resource”1, for example summary details about a
Customer in an XML format.
TODO: Complete terminology list and specify where the terms are non-standard, e.g. idea of representation contract.

Domain

TODO: Enumerate DDD terms used.

Pattern Solution

The following diagram displays the major patterns used by this scenario and the layers where those patterns are implemented.

RestOverDDD_Small.jpg
TODO: Replace with proper diagram
  • Router - A Router pattern maps Uniform Resource Identifiers (URI) to resources.
  • Resource – Every meaningful thing your application that you wish to expose would be considered a resource, for example a Customer with an ID of 5. In the context of this pattern a resource is associated with several artifacts:
    • Handler - HTTP requests are routed directly appropriate methods on this handler for processing.
    • Underlying Model - Each resource is associated with one or more underlying value objects or entities, but users of this resource do not see these underlying classes.
    • Representation Contract - Resources expose one or more representations (e.g. XML/JSON), the representation contract is a class that describes a canonical representation of the resource and it can then be serialized directly into the specific representations that clients receive.
  • Object-Object Mapping – The mapping between the domain model and the representation contracts is done using object to object mapping.
  • Domain Model – DDD patterns including value object, entity, aggregate and (domain) service are used to structure the business logic around one or more models that are shaped by the business domain. The model is inherently behavioral.
  • Unit of Work – A unit of work is used to ensure that all changes to the domain model that are made during a single request are tracked so that they can be committed as on.
  • Session-per-request – Each request made to a resources results in a new unit of work and transaction being created. Thus all updates within a single request must succeed or fail.
  • Repository – Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

End to End Scenario

The following describes a single request being processed:
  1. Client sends an HTTP request, either directly or with the aid of a client-side library that we have written to give access to our RESTful Web Services.
  2. The HTTP request reaches the server and is routed to a method on a resource handler.
  3. When routing the request the framework should pass in any arguments based on query string values or URI path segments. In addition if the request has a body, such as an XML representation of a resource, then this should be deserialized into the correct representation contract class which can be passed into the resource handler method.
  4. The method on the resource handler is responsible for ensuring a transaction and unit of work are created, within that unit of work several actions are performed:
    1. The domain model is updated.
    2. Any other required behavior is fulfilled, for example sending messages so that external systems know about the change.
    3. If any errors occur then the resource handler should roll back the transaction, otherwise it should commit.
    4. The appropriate HTTP status code is used and any required response headers are populated.
  5. If the client-side library was used then it will decide what to do based on the response, for example it might map an error related HTTP status code to an exception.

Pattern Solution Details

The pattern solution identifies primary patterns used by this scenario, broken down by layers in the solution. In each case the textual description is matched with a sample implementation. It is first worth enumerating the technologies used.
Technologies

All a client needs is an HTTP library (such as the one in .NET) to make HTTP calls against our REST facade, but server-side we are using multiple technologies:
  • WCF
  • Castle Windsor– Castle Windsor is an excellent IoC Container.
  • Castle WCF Facility – Out of the box WCF's configuration involves a lot of complex XML, the configuration using this XML is painful and error prone so this addition to Castle provides a fully featured fluent interface to remove much of the pain.
  • NHibernate – A mature and full featured ORM.
  • Fluent NHibernate – Builds on top of Nhibernate, providing a convention based approach to mapping and a fluent interface for specifying your mappings (NHibernate originally only supported XML based mapping definitions)
TODO: Consider using the AutoMapper.

In each case other valid choices exist, for example WCF could be replaced with a framework built on top of MVC and there are many good ORMs and IoC frameworks to choose from.

In addition note that some of these products are open source and we will be using trunk versions of some of them, instead of limiting ourselves to a stable release, in order to show the capabilities of up-to-date versions.

REST Web Service Layer

Every interesting thing that your client might want to link to or interact with becomes a resource. REST can thus thus a modeling exercise where the artifacts you produce include a coherent set of resources.

In this scenario we are using REST over a domain model so this layer is responsible for exposing the required resources and interacting with the domain model.

Router

In this case there are two parts to the solution when applied using WCF.

The first is to define the resource handler interface. This interface helps to associate each method within the handler with a URI, an HTTP Method and a representation format. It also specifies the signatures of the methods that will handle the requests.

TODO: Split into two resource handlers, one for the user collection and one for user.
TODO: Show one of the methods being for JSON.
[ServiceContract(Namespace = "http://www.acompany.com/whatever")]
public interface IUserResourceHandler
{
    [OperationContract, WebGet(UriTemplate = "/{id}")]
    UserContract GetUserById(string id);

    [OperationContract, WebGet(UriTemplate = "/")]
    UserList GetAllUsers();

    [OperationContract, WebInvoke(Method = "POST", UriTemplate = "/")]
    UserContract CreateUser(UserContract userContract);

    [OperationContract, WebInvoke(UriTemplate = "/{id}", Method = "PUT")]
    void UpdateUser(string id, UserContract user);
}
The second part is specifying a host, this associates the resource handlers with particular base URLs. We are using Castle Windsors WCF Facility which has a fluent interface for configuring WCF, in this example we are saying that when a request comes in to “http://www.foo.com/finance/users" we want it to instantiate a UserResourceHandler to handle it:

TODO: Use the new Castle WCF facility, makes this much easier.
Component
    .For<IUserResourceHandler>()
    .ImplementedBy<UserResourceHandler>()
    .ActAs(
        new DefaultServiceModel()
            .AddBaseAddresses("http://www.foo.com/finance/users")
            .AddEndpoints(WcfEndpoint.BoundTo(new WebHttpBinding()))
            .AddBehaviors(new WebHttpBehavior())
        )
Given this host and the interface shown we could use a request like this to get a user with an Id of 2:
GET .../users/2 HTTP/1.1
Content-Type: text/xml
Host: hostname:8080

Representation Contracts

The outside world cannot directly access a resource, instead they can access representations that the resource produces. WCF supports returning XML or JSON representations of resources, both can be generated from a single class and in this document that class is referred to as the representation contract.

An example of a representation contract in the context of WCF is:
[DataContract]
public class UserContract
{
    [DataMember]
    public Int64 Id { get; private set; }
   
    [DataMember]
    public String Logon { get; private set; }
    
    [DataMember]
    public Boolean Locked { get; private set; }
}
We can manually serialize this class to XML using the DataContractSerializer and to JSON using the DataContractSerializer but WCF will automatically use the correct serializer as required.

When considering representation contract design several factors come into play including cacheability of the data, the use standard media types and hypermedia.

Object-Object Mapping

There are two types of object-object mapping we need to consider in this layer, the first is generating a representation contract from the domain and the second is creating or updating the domain based on incoming representation contracts.

Domain to Representation Contract

With domain to resource mapping you just create a new representation contract and populate it from the domain model. How complicated this is depends on several factors including how closely the domain model classes and representation contracts match, but in all cases it is simplified by the fact that the representation contracts are data (rather than behavior) oriented. One possible interface for a simple mapping is shown:

UserContract contract = new UserToContractMapper().MapFrom(user);

Representation Contract to Domain

This is more complicated as whilst the contracts are data-oriented a domain model is also behavioral. Thus when updating your domain model you are not merely setting properties, you may also be calling methods or involving other objects (including domain services) in the update. We thus need a more complex approach, and the fluent interface shown is one way to map changes in a provided data-contract to the domain model.
new UserUpdateHandler()
    .Update(user)
    .BasedOnChangesIn(userContract);
...

public class UserUpdateHandler
{
    private User _user;

    public UserUpdateHandler Update(User user)
    {
        _user = user;
        return this;
    }

    public void BasedOnChangesIn(UserContract userContract)
    {
        HandleIncomingContract
            .When_contract_has(uc => uc.Archived)
                .If_domain_has(user => user.Archived == false)
                    .Update_domain(user => user.Archive())

            .Map_properties_by_name_and_type()

            .Complete_using(userContract)
            .To_update(_user);
    }
}
Alternatives to this approach exist:
  • Generate commands - An alternative approach when processing an incoming contract would be to generate a representation contract from the current state of the domain object(s), this could then be compared it to the incoming contract. Any differences could be turned into custom commands which could then be used to update the domain.
  • Generate Messages - If you are using messaging then you might go a step further and produce messages which could be sent to the domain for processing, these could also be published so that other systems could be alerted to the changes.

Also note that this mapping will have to take care of other concerns (DDD terminology used):
  • Cross Aggregate - If the changes involve updating multiple aggregates then a domain service will be called as part of the mapping.
  • Value Objects - If parts of the incoming representation relate to value objects then new instances of those value objects will need to be created.
  • Invariants - Once all the changes have been applied to all involved aggregates we must ensure that the invariants of those aggregates are fulfilled (that they are valid).

Resource Handlers

TODO: An example showing a request coming in, a transaction, HTTP status codes and the rest.

Domain Layer

Services, Aggregates, Entities and Value Objects

TODO: Simple examples.

Repositories

TODO: Show repository interface and some of the implementation.

Unit of Work, Transactions and Concurrency

TODO: Simple example.

Additional Considerations

Validation

TODO: Document idea of applying validation once in domain, and copying directly to the contracts

WCF and REST

Roy T. Fielding has categorically stated that REST APIs Must Be Hypertext Driven, for a good description of the advantages of HATEOS see Why HATEOAS? and for a worked example showing a RESTful workflow see How to GET a Cup of Coffee.

Unfortunately WCF does not support linking representation contracts to media types and has no out of the box support for providing links in your representations (which is a key aspect of REST). The latter issue causes some problems when designing a RESTful system, for example out of the box there is no support for saying that my UserContract when sent over the wire should contain links to all the RoleContracts it is associated with:

TODO: Xml representation, use ATOM links.

In the situation shown we would like the representation to contain the actual URI's of the roles, but there is no way of directly asking WCF for a link to a particular role.

In fact you will have to build up the links yourself because although WCF has all the information needed to create the links it won't give you access to it directly. In addition the provided extensibility points do not let you directly access the meta-data you've already provided WCF with (through, among other things, the ServiceContract attributes you've applied).

It is thus expected that with current versions of WCF most systems will at most reach REST maturity level 2, however it is entirely possible to build up links within your code as shown in this example.

Additional Resources

Last edited May 18, 2009 at 5:09 PM by colinjack, version 37

Comments

fgaucho Jun 25, 2009 at 10:43 AM 
http://today.java.net/pub/a/today/2009/06/04/exposing-domain-models-part-1.html