0% found this document useful (0 votes)
67 views7 pages

Real Web Services With REST and ICF

Real Web Services

Uploaded by

fziwen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
67 views7 pages

Real Web Services With REST and ICF

Real Web Services

Uploaded by

fziwen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

5/28/2021 Real Web Services with REST and ICF

Real Web Services with REST and ICF SAP Developer Network

Summary
Content Options
DJ Adams is not an SAP employee and the opinions he expresses in this article do not reflect the official opinion or positioning of SAP. E-mail
This
Learn about the Internet Communication Framework, and how to harness it to write your own web services in SAP. Break free from the Document
stranglehold of complexity that SOAP has upon you, and start building real web services with HTTP. Email it
Print
By Dj Adams This
Article
22 Jun 2004 Print it
Add To
Favorites
Add it to
Web Services and SOAP Favorites

There's a lot of hype about SOAP and associated WS-* initiatives being the panacea of data interop over the web. But while the most common
transport of SOAP messages is HTTP, can SOAP be really classed as a 'web' service? There's really nothing web-like about SOAP, except that in
many cases, the standard HTTP port is used -- 'hijacked', almost -- as a tunnel through which to transfer opaque messages to and from a single non-
specific endpoint.

Ok, that was perhaps a little harsh. But as the saying goes, truth hurts. When I think of SOAP I feel very distant from the information I'm trying to
manage. There are just too many mechanisms and far too much protocol in the way. Why employ an application protocol (such as HTTP) and then
only use it to transfer messages between meaningless addresses? It's like buying a car and only using it to store things in.

Let's think about what web services are about. They're about the sharing and exchange of data over the web. What's the biggest, most scalable,
most interoperable, most widely used, most successful example of that? Yes, surprise surprise, it's the web itself. And what powers the web? The
Hypertext Transfer Protocol. HTTP. Sure, there are plenty of key team members that go to make up the full experience ((X)HTML, MIME, CSS,
and so on), but the one essential ingredient that makes everything work, is the application protocol -- not transport protocol -- HTTP.

So if web services are about sharing and exchanging data, what are we trying to achieve? We're trying to open up the data and functionality inside
our SAP systems, in a controlled manner of course, to share with our partners and customers.

Look at this in the context of SOAP. You have an element (or elements) of data that you want to share with your customers. Who in their right
mind would wrap a CORBA-wannabe function call in angle brackets, send the request to an opaque endpoint, expect the receiver to blindly accept
it, and then expect to have to start an XML parser just to get at the reply? People building job security, perhaps? Or with too much time on their
hands?

And another thing. When you're reading or writing data with SOAP, you're not actually addressing that data directly, are you? All you've got is the
address of some faceless SOAP server location with which you must interact. But surely, if an element of data is important enough to share with
your customer, isn't it also important enough to have its own address -- its own URL?

HTTP - The Application Protocol

I pointed out earlier that HTTP is an application protocol, not a transport protocol. That's an important distinction to make here. HTTP is not just
about transporting payloads around. Let's look briefly at what HTTP is all about.

HTTP allows you to manage data, in that it allows you to read (retrieve), write, update and delete it. And as any SQL guru will testify, those are the
four essential fundamentals in any data manipulation mechanism. In HTTP there are verbs and nouns. The verbs -- GET (read), PUT (write),
POST (update), DELETE (ahem, delete) -- reflect the actions that can be carried out on the nouns. The nouns are URLs.

Looking at this in the context of, say, a page of HTML, we could have the following simple scenarios as shown in Figure 1.

Verb Noun Action


GET /some/path/page1.html Retrieve the specified HTML page
PUT /some/path/page1.html Replace the specified HTML page with a new one
Add a new HTML page - the response will indicate where the new page is store(URL) (e.g.
POST /some/path/
/some/path/page2.html)
DELETE /some/path/page1.html Delete the specified HTML page

Figure 1. HTTP verb/noun scenario example

With MIME types allowing us to specific and handle content types of all kinds, HTTP is arguably all we need as a flexible application protocol to
provide all kinds of web services.

Part of the appeal of using real web services is that HTTP is unadorned. What you see is exactly what you want. And what you want, you can get
using a huge array of tools, on a wide range of platforms. HTTP is probably one of the most widely ported application protocols around. There are
all sorts of ways you can construct and execute HTTP requests and parse responses. There are command line tools, like GET and POST (that come
with the fantastic LWP library), which mean that you can combine HTTP requests with your essential shell scripting and pipe-work. There are
libraries for almost every language under the sun. There are even text-mode web browsers that double up as generic HTTP tools. And one of the
most attractive side-effects of HTTP's ubiquity is that there's a plethora of debugging tools out there.

SOAP and Firewalls

Finally, it's worth giving a thought to our poor firewall administrators, whose job it is to analyse traffic and control what enters the enterprise
network. With SOAP, the firewall administrator's toolset is about as much use as a chocolate teapot when it comes to helping police SOAP

https://archive.sap.com/kmuuid2/ea8db790-0201-0010-af98-de15b6c1ee1a/Real Web Services with REST and ICF.article 1/7


5/28/2021 Real Web Services with REST and ICF
requests.

Firstly, in many cases, all SOAP requests, whether they have read-only intentions or write intentions, go to the same endpoint (URL), so no
distinction can be made based on the action (verb) or object (noun). Secondly, even if the firewall software did take the time and effort to open up
the SOAP payload (arguably not the firewall's right), fire up an XML parse to interpret it, and look at the method call being issued, who's to say,
based on the arbitrary name of that method call, what the intention was? (There is the SOAPAction header which is supposed to help here; but for
one thing, it's optional, and for another, even if it was mandatory, the value supplied is as good as arbitrary).

With HTTP, the firewall administrator's job is easier. What's the verb? POST? Ok. What's the noun? /some/path/to/a/data/element. Ok, not allowed.
Job done.

A Simple Web Service in SAP

So, I'd like to balance out this fighting talk with a very simple example of a real web service, implemented using the Internet Communication
Framework (ICF). Before we do, let's look at the context in which the example will sit.

The Internet Communication Framework

The ICF is an essential part of the HTTP framework built into an SAP system. While the Internet Communication Manager (ICM) does the actual
low-level handling of HTTP requests (with kernel-level code), it's the ICF that exposes the ICM features to us, the lowly ABAP programmers,
giving us a fantastic platform on which to build HTTP applications. It gives us a set of core interfaces and classes representing the fundamental
objects in any web server application development environment - the web server itself, the request object, the response object, utilities for
manipulating HTTP data, and so on.

For more information about the ICF, see the relevant section in the online SAP documentation at http://help.sap.com.

With the ICF, you build web applications - web services - by writing a so-called handler. A handler is simply a piece of code, in the form of a class,
that's called by the HTTP framework for requests made to certain URLs. The code interprets the request, and constructs the response. Where does
the BSP technology fit in all of this? Well, the BSP is 'just' another handler, class CL_HTTP_EXT_BSP, pre-written and provided by SAP, a
handler that is called in the case of requests to certain URLs (starting /sap/bc/bsp). It just so happens that the BSP handler is hugely powerful and
is a complete MVC-powered development world within itself - kudos, chaps!

A Simple Handler Class

So let's build a simple handler class to allow authenticated HTTP requests to retrieve (GET) information from the Correction and Transport System
(CTS). I've developed this example in my copy of the free WAS 6.40 testdrive system 'NW4', which is Basis-only, meaning I'm bound to use some
Basis-orientated data unless I develop some custom applications myself. To keep things simple, I'm going to use CTS data.

We're just interested in exposing basic attributes of transport requests and tasks - who the owner is, what type it is, the date, and the short
description. That sort of thing. The exposure will be made through URLs that have this pattern:

http://servername:port/some-path/transport/<requestname>/<attribute>

For simplicity (and to save lookup tables or dynamic jiggery-pokery in the example code), we're going to use the field names from tables E070
(CTS Request / Task Header table) and E07T (CTS Request / Task Short Text table).

So for example, to retrieve the owner of request NW4K900005, all that is needed is an HTTP GET on the following URL:

http://shrdlu.local.net:8000/qmacro/transport/Y6BK039552/as4user

Note that each element of data has its own address. Each element is a noun in the context of HTTP.

The host on which my NW4 system runs is 'shrdlu.local.net', the ICM is listening for HTTP requests on port 8000, and I've defined a namespace
'qmacro' in SICF within which I develop all my test services. Under that namespace I have defined a service object 'transport', for which the
handler class Z_CL_TRANSPORT_INFO is defined. This can be seen in Figure 2.

Figure 2. The definition of the 'transport' service in SICF

Within the handler class we have the code to identify what transport is being requested ('Y6BK039552') and what attribute ('as4user'). The handler
will retrieve the relevant details, and return them in response. Figure 3 shows how that data can be retrieved on the command line, using the GET
command. The owner of request Y6BK039552 in this case is FILDEBRANDT. Figure 4 shows a similar piece of data retrieved via the web
browser.

[dj@hadrian dj]$ GET http://shrdlu.local.net:8000/qmacro/transport/Y6BK039552/as4user

Enter username for NW4 at shrdlu.local.net:8000: developer

Password: ******

FILDEBRANDT

Figure 3. Retrieving data from the command line

Figure 4. Retrieving data from a web browser

Method IF_HTTP_EXTENSION~HANDLE_REQUEST

Classes that are to act as ICF handlers must implement interface IF_HTTP_EXTENSION. This interface has a single method,
HANDLE_REQUEST. It's in this method that you write the ABAP code to work out what's being requested, and what to do to respond to that
request. Figure 5 shows the code in class Z_CL_TRANSPORT_INFO's method IF_HTTP_EXTENSION~HANDLE_REQUEST.

METHOD IF_HTTP_EXTENSION~HANDLE_REQUEST .

https://archive.sap.com/kmuuid2/ea8db790-0201-0010-af98-de15b6c1ee1a/Real Web Services with REST and ICF.article 2/7


5/28/2021 Real Web Services with REST and ICF

* [DATA DEFINITION]

* e07* table data held in transinfo

TYPES:

begin of transinfo,

trfunction TYPE e070-trfunction,

trstatus TYPE e070-trstatus,

as4user TYPE e070-as4user,

as4date TYPE e070-as4date,

as4text TYPE e07t-as4text,

end of transinfo.

DATA:

path_info TYPE string,

w_trkorr TYPE string,

w_attr TYPE string,

w_body TYPE string,

w_fieldname TYPE string,

transportinfo TYPE transinfo.

FIELD-SYMBOLS <fs> TYPE any.

* [INTERPRET REQUEST]

* Look at what is being requested

path_info = server->request->get_header_field( name = '~path_info' ).

SHIFT path_info LEFT BY 1 PLACES.

SPLIT path_info AT '/' INTO w_trkorr w_attr.

* [RETRIEVE DATA]

* Try to retrieve the transport

SELECT SINGLE e070~trfunction e070~trstatus e070~as4user

e070~as4date e07t~as4text

FROM e070

INNER JOIN e07t ON e07t~trkorr = e070~trkorr

INTO transportinfo

WHERE e070~trkorr EQ w_trkorr

AND e07t~langu EQ sy-langu.

* [TRANSPORT NOT FOUND]

* Abort with 404 if the transport can't be found

IF sy-subrc ne 0.

CALL METHOD server->response->set_status(

code = '404'

reason = 'Transport not found' ).

CONCATENATE '<html>'

'<head>'

'<title>Transport not found</title>'

'</head>'

'<body>'

'<h1>Transport&nbsp;'

w_trkorr

https://archive.sap.com/kmuuid2/ea8db790-0201-0010-af98-de15b6c1ee1a/Real Web Services with REST and ICF.article 3/7


5/28/2021 Real Web Services with REST and ICF
'&nbsp;not found</h1>'

'</body>'

'</html>'

INTO w_body.

CALL METHOD server->response->set_cdata( data = w_body ).

EXIT.

ENDIF.

* [SELECT ATTRIBUTE]

* Select desired attribute

TRANSLATE w_attr TO UPPER CASE.

CONCATENATE 'TRANSPORTINFO' w_attr INTO w_fieldname

SEPARATED BY '-'.

ASSIGN (w_fieldname) to <fs>.

* [ATTRIBUTE NOT FOUND]

* Abort with 404 if the attribute cannot be found

IF sy-subrc ne 0.

CALL METHOD server->response->set_status(

code = '404'

reason = 'Attribute not found' ).

CONCATENATE '<html>'

'<head>'

'<title>Attribute not found</title>'

'</head>'

'<body>'

'<h1>Attribute&nbsp;'

w_attr

'&nbsp;not found</h1>'

'</body>'

'</html>'

INTO w_body.

CALL METHOD server->response->set_cdata( data = w_body ).

EXIT.

ENDIF.

* [STORE ATTRIBUTE]

w_body = <fs>.

* [SET CONTENT TYPE]

* So far so good - return attribute value in response body

CALL METHOD server->response->set_header_field(

name = 'Content-Type'

value = 'text/plain; charset=utf-8' ).

* [PUT DATA IN RESPONSE BODY]

CALL METHOD server->response->set_cdata( data = w_body ).

https://archive.sap.com/kmuuid2/ea8db790-0201-0010-af98-de15b6c1ee1a/Real Web Services with REST and ICF.article 4/7


5/28/2021 Real Web Services with REST and ICF

ENDMETHOD.

Figure 5. Z_CL_TRANSPORT_INFO's IF_HTTP_EXTENSION~HANDLE_REQUEST

Step By Step

Let's take the code in Figure 5 step by step. The code is deliberately simplistic and sequential to make it easier to go through in stages. The
subheadings that follow refer to the sections of the same name in the code comments.

DATA DEFINITION

Here we define a structure to hold the CTS data that we're going to retrieve, a few working fields, and a field symbol to use when selecting the
requested attribute later on.

INTERPRET REQUEST

For every incoming HTTP request, a 'server control block' is made available to the handler method in the form of a CL_HTTP_SERVER object.
This object has two significant attributes, one of which is the HTTP request object (REQUEST). We can retrieve all sorts of information about the
incoming HTTP request from this, such as the path information from the URL. In this case, this is anything following what's been defined in SICF
for which this handler is specified (see Figure 2), i.e. "/default_host/qmacro/transport".

So making this call:

path_info = server->request->get_header_field( name = '~path_info' ).

retrieves the path information, which, from the example above, is "/Y6BK039552/as4text". Note that ~path_info isn't really a proper HTTP header
field; in the ICF context it's one of the so-called 'pseudo' header fields, which are just bundled in with the rest of the real header fields for
convenience of access.

Once retrieved, the path information is split into transport number and attribute.

RETRIEVE DATA

Now we've got the desired transport number, we can read tables E070 and E07T for the information.

TRANSPORT NOT FOUND

If the read failed, we assume the request or task cannot be found, and so must respond accordingly. The HTTP response object (RESPONSE) is the
other significant attribute of the control block and can be used to build the HTTP response. Here we do two things. We set the HTTP status, and
supply some friendly HTML in the body in case the request has been made from a browser.

Calling the set_status() method of the response object allows us to specify the HTTP status code and reason. We're setting the well-known "Not
found" status code 404 in this case, with a meaningful reason text.

Following that, some HTML is concatenated and placed in the response body with the set_cdata() method.

Figure 6 shows the response in a web browser to a request for an unknown transport.

Figure 6. Unknown transport result in a web browser

SELECT ATTRIBUTE

At this stage it's time to select the attribute. Although not absolutely necessary, we're translating the attribute name to upper case before using a
dynamic assign to point to the right place in the transportinfo structure.

ATTRIBUTE NOT FOUND

Of course, if an invalid attribute name was specified in the URL, the assign is going to fail, so we respond accordingly, in a similar manner to how
we responded in the case of a request or task not being found. We send back status code 404, with a short explanation of what happened.

STORE ATTRIBUTE

If the attribute was valid, and the assign was successful, then we can retrieve the attribute value from the structure.

SET CONTENT TYPE

We're on the home straight now; all that's needed is to build the response. Here, because the data we're sending back is straightforward text, we set
the content type of the response appropriately. The set_header_field() method of the response object is the antithesis of the get_header_field()
method of the request object, in that it's used to set a header field in the outgoing HTTP response.

PUT DATA IN RESPONSE BODY

In the same way that we used the set_cdata() method to put some HTML in the 404 response, we now use it to place the attribute value in the
HTTP body.

Where to next

https://archive.sap.com/kmuuid2/ea8db790-0201-0010-af98-de15b6c1ee1a/Real Web Services with REST and ICF.article 5/7


5/28/2021 Real Web Services with REST and ICF
The ICF provides all you need to develop your own handlers for your own web applications and services. The simple example here merely
scratched the surface; the best thing for you to do next is take this and expand on it, discovering the wealth of features available to the ABAP
programmer of the 21st century.

For a start, how about dealing with the fact that we really want to avoid people interacting with the transport info URLs using anything other than
GET. It's a fairly straightforward matter to add a bit of code into the "INTERPRET REQUEST" section as shown in Figure 7.

* [INTERPRET REQUEST]

* Look at what is being requested

path_info = server->request->get_header_field( name = '~path_info' ).

* (extended code - start)

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

* Abort if not GET

if verb NE 'GET'.

CALL METHOD server->response->set_header_field(

name = 'Allow'

value = 'GET' ).

CALL METHOD server->response->set_status(

code = '405'

reason = 'Method not allowed' ).

EXIT.

ENDIF.

* (extended code - end)

SHIFT path_info LEFT BY 1 PLACES.

SPLIT path_info AT '/' INTO w_trkorr w_attr.

Figure 7. Extending the INTERPRET REQUEST section for 'GET only'

Here we use the get_header_field() method to retrieve the actual HTTP verb used. It's stored, like the path info, as a pseudo HTTP header. (The
new variable 'verb' is defined in the DATA DEFINITION section as TYPE string). We only want to allow GET, and so reject all others by sending
a status code of 405 in the response, indicating that the method used was not allowed. The HTTP 1.1 specification states that when you return a
status of 405 you must also return a header field in the response, to list the methods that are valid and acceptable for the resource (URL) in
question. This is achieved using the set_header_field() method as shown, before setting the status and reason with set_status(). Figure 8 shows a
typical response, with header lines, to an attempt to POST some data to a transport info URL. (In this case, we're supplying the basic authentication
information via the -C parameter.)
[dj@hadrian dj]$ echo "SOAP sucks" | POST -Se -Cdeveloper:password http://shrdlu.local.net:8000/qmacro/transport/Y6BK039552/trstatus

POST http://shrdlu.local.net:8000/qmacro/transport/Y6BK039552/trstatus --> 405 Method not allowed

Server: SAP Web Application Server (1.0;640)

Allow: GET

Content-Length: 114

Content-Type: text/html; charset=iso-8859-1

Client-Date: Fri, 18 Jun 2004 10:44:18 GMT

Client-Response-Num: 1

Title: Method not allowed

<HTML>

<HEAD><TITLE>An Error Occurred</TITLE></HEAD>

<BODY>

<H1>An Error Occurred</H1>

405 Method not allowed

</BODY>

</HTML>

https://archive.sap.com/kmuuid2/ea8db790-0201-0010-af98-de15b6c1ee1a/Real Web Services with REST and ICF.article 6/7


5/28/2021 Real Web Services with REST and ICF
[dj@hadrian dj]$

Figure 8. Response to an invalid POST request.

A Note on REST

The title of this article mentioned REST. What is REST? It stands for "REpresentational State Transfer" and is an architectural style, not a
protocol per se. The term was coined by Roy Fielding (one of the authors of the HTTP 1.1 specification) in his Ph.D. dissertation looking at the
model of web architecture and defining a framework for understanding that architecture (see the dissertation abstract for more details).

REST's premise is that HTTP has everything we need to implement web services. The ideas and example in this article are driven by the REST
philosophy.

You can read more on REST by following links from the Portland Pattern Repository's RestArchitecturalStyle wiki page.

Final Thoughts

Whether or not you're a fan of SOAP, I hope this has provided food for thought, and showed that there are plenty of facilities at your disposal in
SAP for building Real Web Services.

Copyright © 2005 SAP AG, Inc. All Rights Reserved. SAP, mySAP, mySAP.com, xApps, xApp, and other SAP products and
services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP AG in Germany and in
SAP Developer Network
several other countries all over the world. All other product, service names, trademarks and registered trademarks mentioned are
the trademarks of their respective owners.

https://archive.sap.com/kmuuid2/ea8db790-0201-0010-af98-de15b6c1ee1a/Real Web Services with REST and ICF.article 7/7

You might also like