Blogs

DJ Adams

A new REST handler / dispatcher for the ICF
DJ Adams Active Contributor Bronze: 250-499 points SAP Mentor
Business Card
Posted on Sep. 21, 2009 06:42 AM in ABAP, Beyond SAP, Emerging Technologies, Python, SAP NetWeaver Platform, Scripting Languages, Service-Oriented Architecture

Subscribe.Subscribe
Print. Print
Permalink Permalink
Share

One of the best underlying mechanisms to be introduced into the Basis / NetWeaver stack in the past few years is the Internet Communication Framework (ICF), which is a collection of configuration, interfaces, classes and a core set of processes that allow us to build HTTP applications directly inside SAP.

If you're not directly familiar with the ICF, allow me to paraphrase a part of Tim O'Reilly's Open Source Paradigm Shift, where he gets audiences to realise that they all use Linux, by asking them whether they've used Google, and so on. If you've used WebDynpro, BSPs, the embedded ITS, SOAP, Web Services, or any number of other similar services, you've used the ICF, the layer that sits underneath and powers these subsystems.

One of my passions is REpresentational State Transfer (REST), the architectural approach to the development of web services in the Resource Orientated Architecture (ROA) style, using HTTP for what it is - an application protocol. While the ICF lends itself very well to programming HTTP applications in general, I have found myself wanting to be able to develop web applications and services that not only follow the REST style, but also in a way that is more aligned with other web programming environments I work with.

An example of one of these environments is the one used in Google's App Engine. App Engine is a cloud-based service that offers the ability to build and host web applications on Google's infrastructure. In the Python flavour of Google's App Engine, the WebOb library, an interface for HTTP requests and responses, is used as part of App Engine's web application framework.

Generally (and in an oversimplified way!), in the WebOb-style programming paradigm, you define a set of patterns matching various URLs in your application's "url space" (usually the root), and for each of the patterns, specify a handler class that is to be invoked to handle a request for the URL matched. When a match is found, the handler method invoked corresponds to the HTTP method in the request, and any subpattern values captured in the match are passed in the invocation.

So for instance, if the incoming request were:

GET /channel/100234/subscriber/91/

and there was a pattern/handler class pair defined thus:

'^/channel/([^/]+)/subscriber/([^/]+)/$', ChannelSubscriber

then the URL would be matched, an object of class ChannelSubscriber instantiated, the method GET of that class invoked, and the values '100234' and '91' passed in the invocation. The GET method would read the HTTP request, prepare the HTTP response, and hand off when done.

For a real-world example, see coffeeshop.py (part of my REST-orientated, HTTP-based publish/subscribe (pubsub) mechanism), in particular from line 524 onward. You can see how this model follows the paradigm described above.

def main():
application = webapp.WSGIApplication([
(r'/', MainPageHandler),
(r'/channel/submissionform/?', ChannelSubmissionformHandler),
(r'/channel/(.+?)/subscriber/(.+?)/', ChannelSubscriberHandler),
(r'/message/', MessageHandler),
(r'/distributor/(.+?)', DistributorWorker),
[...]
], debug=True)
wsgiref.handlers.CGIHandler().run(application)

This model is absolutely great in helping you think about your application in REST terms. What it does is help you focus on a couple of the core entities in any proper web application or service -- the nouns and the verbs. In other words, the URLs, and the HTTP methods. The framework allows you to control and handle incoming requests in a URL-and-method orientated fashion, and leaves you to concentrate on actually fulfilling the requests and forming the responses.

So where does this bring us? Well, while I'm a huge fan of the ICF, it does have a few shortcomings from a REST point of view, so I built a new generic handler / dispatcher class that I can use at any given node in the ICF tree, in the same style as WebOb. Put simply, it allows me to write an ICF node handler as simple as this:

method IF_HTTP_EXTENSION~HANDLE_REQUEST.
  handler( p = '^/$'                                          h = 'Y_COF_H_MAINPAGE' ).
handler( p = '^/channel/submissionform$' h = 'Y_COF_H_CHANSUBMITFORM' ).
handler( p = '^/channel/([^/]+)/subscriber/submissionform$' h = 'Y_COF_H_CHNSUBSUBMITFORM' ).
handler( p = '^/channel/([^/]+)/subscriber/$' h = 'Y_COF_H_CHNSUBCNT' ).
handler( p = '^/channel/([^/]+)/subscriber/([^/]+)/$' h = 'Y_COF_H_CHNSUB' ).
  dispatch( server ).
endmethod.

The handler / dispatcher consists of a generic class that implements interface IF_HTTP_EXTENSION (as all ICF handlers must), and provides a set of attributes and methods that allow you, in subclassing this generic class, to write handler code in the above style. Here's the method tab of Y_DISP_COFFEESHOP, to give you a feel for how it fits together:

image

(SET_ENTITY and ENTITY are just helper methods for now).

The classes that are invoked (Y_COF_H_* in this example) all inherit from a generic request handler class which provides a set of attributes and methods that allow you to get down to the business of simply providing GET, POST, PUT and other methods to handle the actual HTTP requests.

Here's an example of the method list of one of the request handler classes:

image

One interesting advantage, arguably a side-effect of this approach, is that you can use nodes in the ICF tree to 'root' your various web applications and services more cleanly, and avoid the difficulties of having different handlers defined at different levels in the child hierarchy just to service various parts of your application's particular url space.

I'd like to end this weblog post with a diagram that hopefully shows what I've been describing:

image
If you're interested in learning more, or sharing code, please let me know. I'm using this for real in one of my projects, but it's still early days.

DJ Adams  Active Contributor Bronze: 250-499 points SAP Mentor (@qmacro): SAP Hacker, Integrator, Author, Bread Maker. Find out more: http://www.pipetree.com/qmacro/


Comment on this article
Comment on this weblog
Showing messages 1 through 11 of 11.

Titles Only Main Topics Oldest First

  • How about OData?
    2010-12-20 12:39:28 Steve Pilon Business Card [Reply]

    I think REST in general is a great addition to SAP's offering. In a more specific fashion, are there any plans to make an OData feed available to query SAP entities?
    • How about OData?
      2010-12-21 00:53:58 Thorsten Franz Business Card [Reply]

      Hi Steve,
      Yes, SAP's Project Gateway is based on REST and OData - see here for more info: http://weblogs.sdn.sap.com/pub/wlg/15899
      Cheers,
      Thorsten
      • How about OData?
        2010-12-21 05:54:46 Steve Pilon Business Card [Reply]

        Thanks for the quick reply, Thorsten.


        As a side and friendly note, the URL you provided points to this very blog post; nothing related to Project Gateway.


        The only resources I found that (very briefly) talk about Project Gateway are:
        - Blog post by Richard Hirsch
        http://weblogs.sdn.sap.com/pub/wlg/21628


        - Vishal Sikka's TechEd Keynote Highlights http://www.sapweb20.com/blog/2010/10/sap-teched-berlin-2010-vishal-sikka-keynote-highlights/


        I definitely look forward to hearing more about Project Gateway, in particular how it pertains to OData as a specific implementation of REST.

        • How about OData?
          2010-12-21 06:10:10 Thorsten Franz Business Card [Reply]

          Oops, that was a copy + paste error. Of course I meant exactly the blog by Dick Hirsch you found on your own.
          The value of Dick's blog lies not in any specifics regarding Project Gateway, but in that it is an excellent discussion of how the REST architectural style and Enterprise Services (or SOAP Web Services) can be complementary in your application landscape, each having its respective key strengths and use cases.
          Cheers,
          Thorsten
  • HTTP Methods
    2009-09-27 04:22:13 steffen schloenvoigt Business Card [Reply]

    Hi DJ,


    very nice and interesting article! Thank you!
    While reading it, I wondered if it would be possible to catch the other HTTP methods like PUT, POST and DELETE with this approach. This way it would be possible to create real RESTful web services concerning ressources as collections and members. This is described very nicely in the wikipedia article on REST.


    Kind regards,
    Steffen

    • HTTP Methods
      2009-09-27 04:35:45 DJ Adams Business Card [Reply]

      Hi Steffen, thanks for the comments.


      To answer your question - absolutely, that's sort of the whole point of this mechanism. It will dynamically call a method in the derived class, where the name of the method corresponds to the HTTP method used in the request. See this excerpt from Y_HANDLER_DISPATCHER_GENERIC's DISPATCH method:


      method = server->request->get_header_field( '~request_method' ).


      [...]


      call method derive_handler
      exporting path = path
      importing class = handlerclass
      matches = matches
      .


      [...]


      * Call handler method (GET, POST, etc)
      try.
      call method lo_handler->(method)
      parameter-table lt_meth_parm
      exception-table lt_meth_excp.


      [...]


      Hope that explains things a bit better. I am indeed using this feature in my SAP implementation of coffeeshop (http://wiki.github.com/qmacro/coffeeshop) that I'm currently building.


      Regards
      DJ

  • Good dispatching mechanism
    2009-09-26 13:00:49 Thorsten Franz Business Card [Reply]

    Hi DJ,
    I enjoyed your blog because it transports the clarity of the REST approach very well. (So REST should be an ideal match with SAP's recent overall striving for "clarity". ;-))
    In a recent discussion with @ttrapp, I argued that it would be wrong to create a custom dispatching mechanism because the ICF service tree and its configuration are exactly that - a dispatching mechanism deriving handler classes from request URLs. I was completely wrong. Your mechanism is much better for RESTful applications than anything one could accomplish within the restrictions (or limited to the first-degree tools of) the ICF tree.
    I also enjoyed the code samples from gisthub and hope that you will keep us all posted about your project.
    Cheers (to Clarity!),
    Thorsten
  • great post
    2009-09-21 20:39:28 Juergen Schmerder SAP Employee Business Card [Reply]

    Hi DJ


    Thanks for this great post on REST and ICF! When it comes to REST@SAP, you are the No 1 evangelist. Meanwhile we've got a small group of REST-enthusiasts assembled at SAP Labs and I'd really like to learn more about your handler.
    Let me know if you can share the code.


    cheers, Juergen

    • source code
      2009-09-23 00:27:24 DJ Adams Business Card [Reply]

      Hi Juergen


      Thanks for the comments. REST is incredibly important for the enterprise. A lot of people still just don't know it yet, though ;-)


      In the spirit of 'release early, release often', I've created a SAPlink nugget, and I've put it here, for now:


      http://www.pipetree.com/~dj/2009/09/NUGG_QMACRORESTHANDLERDISPATCHER.nugg


      In the meantime, have a look at http://gist.github.com/190363 and http://gist.github.com/190364 - two gists that give you the idea (the gist!) of what's going on.


      Kind regards
      DJ


Showing messages 1 through 11 of 11.