Technical Articles
A new REST handler / dispatcher for the ICF
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:
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:
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:
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.
For more information on the coffeeshop mechanism, checkout the videos in this playlist:
Update 01/05/2012 I’ve re-added images to this post that were lost when SDN went through the migration to the new platform. This project is now called ADL – Alternative Dispatcher Layer and is on the SAP Code Exchange here: https://cw.sdn.sap.com/cw/groups/adl
Update 09/09/2020 Added a link to the coffeeshop playlist
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
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
Hello DJ,
I know that its been a couple of years but I noticed that the SAPLink nugget address is no longer valid. Is there some other place where I can find this info? It's also difficult since all the images in the article are also missing. I don't know if this is an issue with my browser of not. I hope its still available - aut viam inveniam aut faciam
Regards,
Mark
Hi Mark
You're in luck - the code is in the SAP Code Exchange in a project of its own now. See https://cw.sdn.sap.com/cw/groups/adl for more details. Post a message in the group if you need any more info or help.
Cheers
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
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
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
Yes, SAP's Project Gateway is based on REST and OData - see here for more info: A new REST handler / dispatcher for the ICF
Cheers,
Thorsten
as far as I understand REST archticture it is based on URI adressing of business object and collection of busines objects with are maniqulate by the HTTP-Methods PUT, GET, REPLACE and DELETE which can be map to CRUD functions.
How can I process complex business logic in REST based style?
All the best,
Guido
reference
http://en.wikipedia.org/wiki/REST
my understanding is that many but not all functions an SAP system may expose can be naturally mapped to the REST architectural style.
REST is not necessarily the right style for all types of applications, and is therefore complemented by Enterprise Services.
Dick Hirsch's wrote a very good blog on this topic: The specified item was not found..
Cheers,
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
The specified item was not found.
- 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.
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
HI DJ,
I just used this solution together with Uwes ZJSON in a project and it runs out of the box.
Great!
Learned a lot by reading the code.
Thanks a lot!
Regards
Renald
Part II #sitHH : Exposing data to #UI5 without using SAP Gateway, Part II: back to standard