Contents tagged with OpenRasta

  • What I like about OpenRasta

    After having playing with the current bits of OpenRasta (OR) for a while, I  am now able to see great advantages in using this framework over other existing frameworks for building RESTful services such as WCF or the ASP.NET MVC.

    Let’s explore some of the good features that make OpenRasta an excellent alternative at the moment of developing RESTful services.

    1. Clean separation of resource representation from service implementation

    If we take a look at a service implementation in OR, the operations in a handler receive or return a resource, but they never specify the final representation of that resource. Resource representation is a pure responsibility of the encoders configured for service implementation (a handler in OR).

    In that way, we have a service implementation completely reusable for different resource representations.

    public class CustomerHandler

    {

        public OperationResult Get(int customerId)

        {

            return new OperationResult.OK

            {  

                ResponseResource = "Customer with id " + customerId

            };

        }

    }

    Once we have the service implementation, we only need to configure the encoders for that service, which could be encoders for Xml, Json, Atom or any other representation. You are free to configure all the encoders you want for the same handler.

    ConfigureServer(() => ResourceSpace.Has.ResourcesOfType<Customer>()

        .AtUri("/customer/{customerId}")

        .HandledBy<CustomerHandler>()

        .AndTranscodedBy<OpenRasta.Codecs.JsonDataContractCodec>(null));

    This is a different story in WCF. First of all, the content type (Xml or Json) has to be specified as part of the operation definition. If we want to support different content types, we need to replicate the same operation only to change the content type. Although this point has been improved considerably in WCF 4.0, some service implementations are still absolutely tied to the resource representation. For example, an operation that returns syndications feeds. In WCF, we have to return a concrete implementation of System.ServiceModel.Syndication.SyndicationFeedFormatter. It is not a simple as return a collection of entities or resources and specify somewhere that we want to represent them as entries in a feed.

    This works much better in ADO.NET data services, where you can just return a resource or a collection of resources, and the framework itself will chose the best representation according to what the client initially sent in the “Accept” header. That representation could be Json or Atom, nothing changes in the service implementation (which is also automatically implemented). However, ADO.NET data services provide few extensibility points today for injecting custom code, and that is probably a good reason to move to OpenRasta.

    2. URI resolution

    In OpenRasta, the URI resolution to a handler is also part of the service configuration. This gives a great flexibility to have many URIs that resolve to the same resource instance.

    A typical example is a parent-child relationship, for instance, a customer/orders relationship.

    You might want to have different URIs to get access to the orders,

    Customer/1/Orders/1 => Give me the order number 1 for the customer with ID 1

    Or you might want to access to the order directly

    Orders/1 => Give me the order number 1

    In OR, you have a single handler implementation for orders (order is the resource in this case), and multiple URIs that resolve to an operation in that particular handler.

    ConfigureServer(() => ResourceSpace.Has.ResourcesOfType<Order>()

        .AtUri("/customer/{customerId}/Orders/{orderId}")

        .AndAt("/orders/{orderId}")

        .HandledBy<OrderHandler>()

        .AndTranscodedBy<OpenRasta.Codecs.JsonDataContractCodec>(null));

    This is a problem in WCF because the URI template is tied to the operation definition, if you want to have different URIs for the same resource, you basically have to copy/paste the same operation just to change the URIs.

    [WebGet(UriTemplate="/Orders/{orderId}")]

    public Order GetOrderById(int orderId)

    {

      //implementation

    }

    [WebGet(UriTemplate = "/Customers/{customerId}/Orders/{orderId}")]

    public Order GetCustomerOrder(int customerId, int orderId)

    {

      //implementation

    }

    So, you will have as many operations as URI and content types you want to support in the service.

    Read more...

  • OpenRasta, an open source alternative for developing Restful services

    OpenRasta (OR) is the name of a new open source framework for developing Restful applications (Web applications or services) created by Sebastien Lambla. As the ASP.NET MVC, this framework is also an implementation of the MVC pattern, which focus mainly on a good separation of concerns, and provide different extensibility points where the developer can plugging custom code at the moment of developing applications.

    The framework is now on Beta 2 stage, Sebastien and other guys are currently working on improving the hosting infrastructure and public API. They are, of course, very open at this point to receive feedback or suggestions for new features, or improvements to existing ones. If you have some interest in participating of this project, you can start joining the mailing list.

    In order to understand how OR works under the hood, I will start by describing some basic concepts that a developer should know to implement an application from scratch with this framework.

    Handlers

    A “handler” is one of the main building blocks in OR. It represents the implementation of the service itself, and it is generally mapped to single resource through an URI. Therefore, any access to an URI will get resolved by OR to an specific handler.

    From an implementation point of view, a handler is simple class that expose methods for handling different http verbs. By convention, a method should be called as the Http verb that supports, for example, Get or Post. However, nothing prevent you from giving more friendly names to the methods (or handler operations), there is an special custom attribute “HttpOperationAttribute” that you can use to associate the method with an http verb.

    public class CustomerHandler

    {

        public Customer Get(int customerId)

        {

            return new Customer { FirstName = "foo", LastName = "bar" };

        }

        public OperationResult Put(int id, Customer customer)

        {

            return new OperationResult.Modified { ResponseResource = customer };

        }

        [HttpOperation(HttpMethod.POST)]

        public OperationResult MyFriendlyMethod(int id, Customer customer)

        {

            return new OperationResult.Modified { ResponseResource = customer };

        }

    }

    If you want to have a better control of the Http status code, as it is shown in the code above, you can also return an instance of OperationResult.

    Codecs

    As you can see, the handlers have not been wired to any content type at this point. Serializing/Deserializing a resource instance into an specific representation is responsibility of the codecs. Some codecs are provided out of the box in OR, for example, Json, Xml, Html or Form-Url-Encoded data.

    A codec generally implement two interfaces, IMediaTypeReader (for deserializing content) and IMediaTypeWriter(for serializing). The following code shows the implementation of the Json codec,

    [MediaType("application/json;q=0.5", "json")]

    public class JsonDataContractCodec : IMediaTypeReader, IMediaTypeWriter

    {

        public object Configuration { get; set; }

        public object ReadFrom(IHttpEntity request, System.Type destinationType, string paramName)

        {

            DataContractJsonSerializer serializer = new DataContractJsonSerializer(destinationType);

            return serializer.ReadObject(request.Stream);

        }

        public void WriteTo(object entity, IHttpEntity response, string[] paramneters)

        {

            if (entity == null)

                return;

            DataContractJsonSerializer serializer = new DataContractJsonSerializer(entity.GetType());

            serializer.WriteObject(response.Stream, entity);

        }

    }

    Putting Handlers and Codecs together

    By means of a fluent configuration, we can later wire up an URI with the corresponding handler and one or more codecs according to the content-types that the service should support.

    ConfigureServer(() => ResourceSpace.Has.ResourcesOfType<Customer>()

                              .AtUri("/customer/{id}")

                              .HandledBy<CustomerHandler>()

                              .AndTranscodedBy<OpenRasta.Codecs.JsonDataContractCodec>()

                              .AndBy<OpenRasta.Codecs.XmlSerializerCodec>());

    This is one of the big differences with the ASP.NET MVC or the Web Programming Model in WCF.

    In the MVC, the supported content types are inherently tied to the ActionResult returned by the controller action. Therefore, the action implementation must be modified in order to support new content types.  Or a more specialized implementation of an ActionResult is required, which has to be smart enough to accommodate these changes.

    Same thing happens with WCF, you have to either decorate the service operation with the supported content-type (Only Json or Pox supported today) or return a Message/Stream instance from the operation and write the resource representation yourself in the operation implementation. As I said, only Json/Pox are supported today, and adding new content types is something complicated to do. You basically need to write a custom IDispatchMessageFormatter extension, and a custom WebServiceHost to replace the formatter provided out of the box. (This is the approach taken in the WCF REST Starter kit for supporting form-url-encoded data).

    Pipeline Contributors

    Let’s go back to OpenRasta for a moment, “Handlers” and “Codecs” are not the only supported extensibility points in this framework. All the processing of incoming/outgoing messages is performed in a pipeline that contains contributors or filters. A pipeline contributor perform simple tasks such as initializing the security context, routing the messages or processing exceptions to name a few. You can write your own contributors, or customize the pipeline to support different configurations or scenarios

    More information about OpenRasta 

    You can find more information about this framework in the Sebastien’s blog. The current project status is also available here.

    Read more...