我的静态博客

Is REST the future for SOA?---Posted by Boris Lublinsky on Aug 11, 2011

It seems like everywhere we turn we keep hearing that SOA’s future is REST. There are a lot of publications comparing REST to SOAP and WS*[1], but such comparison seems to be too simplistic. There are two main approaches that have emerged lately – true REST and REST as a technology approach for services (aka REST Web Services[2]). In this article I will try to discuss whether either of these approaches can improve SOA implementations.

True REST for SOA

A true REST is effectively an implementation of Resource-Oriented architecture and not a pure technology decision. So the right question to ask when discussing true REST is whether its underpinning – ROA - is a good fit for your SOA implementation.

In order to assess the problem correctly, let’s first recall that the SOA architectural style [2] is based on a functional decomposition of enterprise business architecture and introduces two high-level abstractions: enterprise business services and business processes. Enterprise business services represent existing IT capabilities (aligned with the business functions of the enterprise). Business processes, which orchestrate business services, define the overall functioning of the business.

REST, on another hand, is a set of architectural guidelines [3] expressed as Resource-Oriented Architecture (ROA). ROA is based upon the concept of resources; each resource is a directly-accessible distributed component that is handled through a standard, common interface. So, the foundation of ROA is a resource-based decomposition[3].

In order to assess the applicability of true REST for the implementation of SOA, the real question that we need to answer is “What is the relationship between a service and a resource?”

Services vs. Resources

What is a service?

In the simplest case, a service can be defined as a self-contained, independently developed, deployed, managed, and maintained software implementation supporting specific business-relevant functionality for an enterprise as a whole and is "integratable" by design. A “Service” is defined by a verb ( For example, “validate customer’s credit score”, which describes the business function it implements.)

A service is not a programming construct or a set of APIs, but rather an architectural (unit of design, implementation, and maintenance) and deployment artifact used for implementation of enterprise solutions. The service functionality is defined by a service interface (specific for a given service), which can be supported by multiple implementations. There are two basic ways of defining a service interface – RPC-style and messaging-style. RPC-style implementations use service invocation semantics and are defined through a set of parameters in the service interface. In the case of messaging style, a service interface is effectively fixed – it essentially performs “execute” - with an XML document as input and output (much like the GoF command pattern). A service semantic, in this case, is defined by the semantics of the input and output messages[4].

Historically, services are often defined as a collection of methods, but as explained in [2] these methods are independent from each other[5] and such collection serves as a namespace, simplifying the management of the services.

What is a resource?

In the simplest case, a resource can be defined as a directly-accessible, independently-developed, deployed, managed and maintained software artifact supporting specific data. A resource is defined by a noun for example, “doctor’s appointment” that describes the data provided by the resource. A resource can also relateto other resources and provide a reference (link) to them. In effect, a resource is similar to an object[6], but with a predefined (CRUDish) interface semantic.

The semantics in REST are based on the set of HTTP operations and looks as follows [5]:

  • createResource - Create a new resource (and the corresponding unique identifier) - PUT
  • getResourceRepresentation - Retrieve the representation of the resource - GET
  • deleteResource - Delete the resource (optionally including linked resources) - DELETE (referred resource only), POST (can be used if the delete is including linked resources)
  • modifyResource - Modify the resource – POST
  • getMetaInformation - Obtain meta information about the resource - HEAD

A resource is defined by its URL and definition of inputs/outputs for every operation supported by a resource[7]. Unlike a service, where methods are completely independent and can be deployed as independent endpoints, methods on a resource follow OO semantics, which means that all of them (except createResource) have to exist on the underlying resource (same URL).

Basic differences between Resources and Services

Based on the above definitions of resources and services, it seems intuitively obvious that they are very different. Let’s delve into these differences first, and then discuss how they can impact resulting architecture.

As stated in [6]:

“Not only is REST not service oriented, service orientation is irrelevant for REST”

And [7] goes even further explaining the differences between the two as:

“If WS-* is the RPC of the Internet, REST is the DBMS of the internet… Traditional SOA based integration visualizes different software artifacts being able to interact with each other through procedures or methods. REST effectively allows each software artifact to behave as a set of tables, and these artifacts talk to each other using SELECT, INSERT, UPDATE and DELETE. ( or if you wish GET, PUT, POST, DELETE). And where exactly is the business logic? Is it in the stored procedures? Not Quite. It’s in the triggers.”

Here we will use a slightly different analogy, one based on J2EE. We can think of services as stateless session beans and resources as entity beans.

Services – session beans – serve as controllers allowing execution of a required operation, regardless of the underlying resource. For example, a debit account service might take the account ID and the amount and debit required account. A single service can debit any of the existing accounts.

Resources – aka entity beans – serve as a data access mechanism for a given instance of given data type. For example, in order to debit a certain account, it is necessary to find a resource representing this account and then update it to debit the required amount. An additional caveat here is that unlike an entity bean which can implement any required method, a REST resource has only a single modify resource method. This means that the actual business operation, the debit, has to be encoded as part of the request.

What does this mean?

Based on the above, it is impossible to build an SOA system using true REST. It is possible to build a system, but it won’t be SOA. Both will start with the business-aligned decomposition, but because they are using very different decomposition approaches they will result in completely different architectural styles[8] based on different set of components and connectors.

Just because they are trying to solve the same problem – business/IT alignment and are both based on business driven decomposition does not mean that the result will adhere to the same architectural style.

Another question is whether it is possible to build a complete system using true REST. Based on the above, it is a question of whether it is possible to build a complete system using only a database or entity beans. Certainly you could, but it would require adding procedural code in the form of stored procedures (overwriting the meaning of the methods) or triggers (doing post processing based on the data changes). The same is typically true for a true REST implementation – you have to change the meaning of the modifyResource method (often using command pattern) to do more than data update.

As a result, a REST-based implementation is rarely true REST; it typically includes at least some elements of REST Web Services. So what does it mean to be a REST Web Service?

REST Web Services

The REST Web Service approach is an approach for using REST purely as a communication technology to build SOA. In this case, services are defined using SOA style decomposition and REST-based Web Services[9] are leveraged as a transport.

Although commonly referred to as REST, this approach has nothing to do with true REST and is similar to POX (plain old XML over HTTP), with the difference being that in addition to XML, it supports multiple other data marshalling types ranging from JavaScript Object Notation (JSON) to ATOM to binary blobs and leverages additional HTTP methods, compared to POX, which is typically based on GET and PUT.

Using JSON became a very popular approach due to the advances of Web and wide-spread adoption of Ajax technology; the majority of modern browsers have built-in support for JSON. Since it is a non-trivial task to process XML (especially with multiple namespaces) in JavaScript, it is much easier for web-based implementations to use JSON-based REST Web Services. The proliferation of REST Web Services for Web interactions lead to the increased popularity and wide spread of these technologies.

What is the real difference?

Publications describing differences between SOAP and REST typically point to the following advantages of REST Web Services, for example [11]:

  • “Lightweight – not a lot of extra xml markup
  • Human Readable Results
  • Easy to build – no toolkits required”

Although these differences are important (I will discuss them in detail later in the article), the main difference between SOAP and REST is the fact that while REST is implemented directly on top of the HTTP protocol, SOAP introduces an abstraction layer (SOAP messaging), that can be implemented on top of any transport. Standardized SOAP bindings currently exist for HTTP, SMTP and JMS, but non-standard bindings have been implemented for other transport solutions. This additional abstraction layer that provides decoupling between existing transports and SOAP-based implementations is the root cause of major differences between SOAP and REST Web Services.

The opinions about this abstraction layer vary significantly depending on whom you talk to. The REST camp considers it to be over-engineering and claims that it does not provide any real value. They claim that HTTP already provides all of the features required for implementation of services interactions. The SOAP camp, on the other hand, will argue that HTTP is not the only transport that is typically required for service interactions (especially inside the enterprise) and having a portable, extensible[10] abstraction layer is necessary for building robust, feature-rich service interactions.

Although both points of view have their merits, in my experience trying to limit SOA implementation to a single transport – HTTP - rarely works in practice. Yes, HTTP is ubiquitous and its usage typically does not require any additional infrastructure investments, but it is not reliable (HTTP-R is not widely adopted), synchronous only[11] (creating temporal coupling), does not have transactional semantics and so on.

Additionally, even if HTTP is the only transport used in implementation, the SOAP envelope can become very handy for a clean separation of business (SOAP Body) and infrastructure or out-of-bound (SOAP Headers) data in SOAP messages. And finally, if your original implementation does not require any infrastructure or out-of-bound data, the overhead of the SOAP envelope is minimal – two tags, but provides a well-defined way for adding such data as the need arises.

So, at the end of the day, data enveloping with separation of business and infrastructure concerns is a very powerful paradigm, which is often used even in the REST Web Services implementations. Whether to use a standardized SOAP or a custom enveloping schema[12] has to be decided by a specific implementation.

Other differentiators

Let’s take a moment to discuss some of the other differentiators between SOAP and REST Web Services often cited in publications.

Simplicity

A popular opinion is that REST is much simpler then SOAP. According to them, REST simplicity stems from the fact that REST does not require WSDL or any interface definition. Such statements are naïve, at best. No matter which technology is used for communications between service consumer and provider, they must still agree on both syntax and semantic of their message exchange (interface)[13]. This means that in the case of REST, one of two approaches is possible:

  • Defining an interface in a text document and “manually” coding of data marshalling/unmarshalling based on a common interface definition described in the interface document. Although such an approach is often promoted by REST advocates, it rarely scales beyond 10 - 15 elements, which is not typical for coarse grained REST services. Besides, such an approach is very error prone and as a result, most of the available REST frameworks have abandoned it in favor of the next approach.
  • Defining an interface on the XSD level and generation of the data marshalling/unmarshalling based on the preferred framework (for example, JAXB or Castor in the case of XML payload or Jackson, in the case of JSON payload). Such an approach is, in effect, a minimalistic version of WSDL and requires about the same amount of effort as SOAP-based implementations. In fact, exactly the same approach is often used in the SOAP-based implementation, leveraging a single interface and a command pattern for service execution. The extension of this approach is usage of WSDL2.0 [13] and/or WADL [14] for REST.

Another common complaint about SOAP is perceived complexity of WS* standards [15]. Although there is no single spec that lays out the key WS*standards and their interrelationships, there is a standard for a majority of service interaction use cases. Granted, the choosing of an appropriate WS*standard and its usage might require some extra understanding/implementation time, but [16]:

“Arguing simplicity versus standards is ridiculous in the war between REST and SOA because simplicity without standards is just as detrimental to the costs and manageability of an application “

So, with the exception of the most simplistic examples like “temperature converters”, REST is not any more simple than SOAP.

Lightweight

Another reason why many REST proponents are advocating REST as an alternative to SOAP is the fact that in REST, both requests and responses can be short. There are two main reasons for this:

  • SOAP requires an XML wrapper around every request and response, which increases the size of a message. Although this is true, the important thing to consider here is not how many bytes the wrapper adds, but rather the percentage of overhead it creates. Because the wrapper size is constant, this percentage decreases as the size of the message grows, eventually becoming negligible. Considering that a typical service is fairly coarse-grained, the size of the request and reply is fairly large and consequently the overhead of a SOAP envelope is rarely an issue.
  • SOAP is XML-based messaging, which uses verbose encoding. REST, on the hand, provides a more lightweight messaging alternative – JSON[14]. Although this is true, usage of the Message Transmission Optimization Mechanism (MTOM) [17], supported by most SOAP frameworks, allows for splitting of messages into minimal XML-based SOAP Envelope/Header/Body parts and additional parts containing message content that can be encoded as any MIME types, including JSON, binary streams, etc.

Although in theory, REST is lighter-weight compared to SOAP, in practice, with some advanced SOAP design techniques, the difference between size of realistic SOAP and REST messages can be made minimal.

Easy to build – no toolkits required

Because REST is based on HTTP, one of the claims of its proponents is that one can use familiar technologies like the Java servlet API and Java HTTP support to write REST services implementations and clients without any specialized toolkits. This is true if one wants to “manually” implement building input/output messages and data marshalling. The same can be done for SOAP Web Services as well. However, people rarely want to write such boilerplate code and as a result use toolkits for both SOAP and REST [18].

Conclusion

REST can be used as both system design approach leveraging ROA (true REST approach) and SOA design implementation leveraging REST technologies (REST Web Services). Although both approaches have their merits, they do not change the hardest part– defining business services/resources aligned with the enterprise business model. There are cases for both SOA and ROA, but at the end of the day those are two very different styles.

About the Author

Boris Lublinsky is principal architect at NAVTEQ, where he is working on defining architecture vision for large data management and processing and SOA and implementing various NAVTEQ projects. He is also an SOA editor for InfoQ and a participant of SOA RA working group in OASIS. Boris is an author and frequent speaker, his most recent book "Applied SOA".

Acknowledgements

I am thankful to my NAVTEQ colleagues, especially Jeffrey Herr for help in writing this article. Also thanks to Stefan Tilkov and Kevin T. Smith for providing interesting feedback (often negative), that helped me to improve the article

jrest4guice is a lightweightRestful service framework, and it supports JPAJAAS and distributed resource object.


Features:

  • Based on Google guice
  • Zero configurationscan and register services automatically
  • Noninvasive, users needn't implement certain interface to achieve Restful service(just use @RESTful annotation)
  • Support PostGetPutDelete operation
  • Support caching mechanisms for Get operationstaticize dynamic resourceuse @Cache annotation to declare
  • Flexible injection(support context request/response/session and automatic injection of parameters)
  • Return different types of data(like xml/json/html) according to the different client
  • Use @PageFlow to achieve the support of MVC module2, the output can be CTEVelocityFreemarker and Spry template engine(only when return type is text/html, can it be valid )
  • Support JPA, use enhancive BaseEntityManager to achieve the CRUD of entity
  • Support transaction, use @Transactional annotation to declare the type of transaction
  • Support JAAS,use @RolesAllowed annotation to manipulate the needed rose
  • Support Hibernate validator
  • Support interceptor
  • Support distributed resource object, achieve distributed deployment of business logic
  • Support plugin to integrate with Struts2

Code example:

//=======================================================
//resource class
//=======================================================

/**
 * @author <a href="mailto:zhangyouqun@gmail.com">cnoss (QQ:86895156)</a>
 * resource object of the contact
 * set remoteable to true
use @RemoteReference annotation to inject into any
 * resource object, and it usually used to resource invoke between cross-applications

 */
@RESTful(name = "ContactResource", remoteable = true)
@Path( { "/contact", "/contacts/{contactId}" })
public class ContactResource {
   @Inject
   private ContactService service;//inject contact management service
   /**
   * create a new contact
   *
PageFlow When server-end returns Text/Html, it redirects user’s request to given page, achieve the most basic of MVC function.
   *
Here, if success, redirect the user request to "/contacts";if failure, redirect it to "/contact"
   * @param contact
   */
   @Post
   public String createContact(@ModelBean Contact contact) {
     return this.service.createContact(contact);
   }

   /**
    * modify contact information
    * @param contact
   */
   @Put
   public void putContact(@ModelBean Contact contact) {
      this.service.updateContact(contact);
   }

   /**
    * show contacts list
    * @param page  page number
    * @param size  number of records per page
   */
    @Get
    @Path("/contacts")
    public Page<Contact> listContacts(int page, int size) {
      return this.service.listContacts(page, size);
    }

    /**
     * show specific contact information
     * @param contactId
     */
    @Get
    public Contact getContact(@Parameter("contactId") String contactId) {
      if(contactId == null)
        return new Contact();
     return this.service.findContactById(contactId);
  }

  /**
   * delete specific contact information
   * @param contactId
  */
  @Delete
  public void deleteContact(@Parameter("contactId") String contactId) {
    this.service.deleteContact(contactId);
  }
}

//=======================================================
//business class
//=======================================================


/**
 *
 * @author <a href="mailto:zhangyouqun@gmail.com">cnoss (QQ:86895156)</a>
 *
 */
@Transactional//Default value is TransactionalType.REQUIRED
it can be overrided  in method
@Interceptors({
//self-defining interceptors(class-levelit works on all methodsand can be override in method
          @Interceptor(TestInterceptor.class),
          @Interceptor(LogInterceptor.class)
})
public class ContactService{
   //inject entry management
  @Inject
  private BaseEntityManager<String, Contact> entityManager;

  public String createContact(Contact contact) {
    if (contact == null)
       throw new RuntimeException("the content of contact can not be null");

    if (this.entityManager.loadByNamedQuery("byName", contact.getName()) != null) {
       
throw new RuntimeException("You have input a duplicate contact nameplease enter again");
    }

    this.entityManager.create(contact);
    return contact.getId();
  }

  public void deleteContact(String contactId) {
    String[] ids = contactId.split(",");
    Contact contact;
    for (String id : ids) {
      contact = this.findContactById(id);
      if (contact == null)
         throw new RuntimeException("contact not exist!");
         this.entityManager.delete(contact);
    }
  }

  @Transactional(type=TransactionalType.READOLNY)
  public Contact findContactById(String contactId) {
      return this.entityManager.load(contactId);
  }

 
@Transactional(type=TransactionalType.READOLNY)//override class-level TransactionalType to READOLNY
  @Interceptor(ListContactsInterceptor.class)//override class-level Interceptor
  public Page<Contact> listContacts(int pageIndex, int pageSize) throws RuntimeException {
     
return this.entityManager.pageByNamedQuery("list",new Pagination(pageIndex, pageSize));
  }

  public void updateContact(Contact contact) {
    if (contact == null)
      throw new RuntimeException("the content of contact can not be null");
               
      Contact tmpContact = this.entityManager.loadByNamedQuery("byName", contact.getName());
      if(tmpContact != null && !contact.getId().equals(tmpContact.getId()))
       
throw new RuntimeException("You have input a duplicate contact nameplease enter again");

      this.entityManager.update(contact);
   }
}


//=======================================================
//a case of remote call
//=======================================================

/**
 *
 * @author <a href="mailto:zhangyouqun@gmail.com">cnoss (QQ:86895156)</a>
 *
 */
@Path( { "/testCallRemote"})
public class TestRemoteResource {
  @Inject
  @RemoteReference//inject remote resource object
  private ContactResource service;

  @Get
  public Page<Contact> listContacts(int page, int size) {
    return this.service.listContacts(page, size);
  }
}

you can get the JRest4Guice source code from svn(use maven)

We sincerely hope that you will give us your valuable criticisms and suggestions,contact information:

  • Emailzhangyouqun@gmail.com
  • QQ: 86895156
  • MSN: zhangyouqun@hotmail.com

 

posted @ 2014-08-14 15:27  myplist  阅读(168)  评论(0编辑  收藏  举报