Friday 29 June 2018

Writing a SICF service

Introduction


This blog will guide you through the process of creating a SICF service (REST). SICF is an SAP transaction which is used to maintain services for HTTP communication, using the Internet Communication Manager (ICM) and the Internet Communication Framework (ICF). This can be useful in multiple situations. For example: A certain system might not have the proper Gateway installation or configuration to create services there.

Following steps will be taken to create and test such a service:

◈ Creating a structure and table type
◈ Creating the ZIF_REST Interface.
◈ Creating a Handler Class
◈ Creating the class for a GET Request
◈ Creating the class for a POST Request
◈ Creating a node in transaction SICF
◈ Testing the GET service
◈ Testing the POST service

1. Creating a structure and table type


Let’s create a structure for the entries we want to get later on.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Create a table type for that structure.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

2. Creating the ZIF_REST Interface.


To start off with, let’s create an interface in ‘SE24’ (if it doesn’t exist yet) which we will use for almost all classes in this guide. The interface consists of two methods, one for the request and one for the response.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

The method ‘SET_RESPONSE’ has an importing parameter ‘IS_DATA’ with the ‘XSTRING’ type. Make sure you activate the interface.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

3.Creating a Handler Class


Go to ‘SE24’ and create a new class. Select the tab ‘Interfaces’ and add interface ‘IF_HTTP_EXTENSION’.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Go back to the tab ‘Methods’ and you’ll see a method has been added. Add another method called ‘GET_REST’.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Add the following parameters to the method ‘GET_REST’.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Copy the following code to your method ‘IF_HTTP_EXTENSION~HANDLE_REQUEST’.

It will execute the ‘GET_REST’ method to get the class we want to execute to get or process the data.

METHOD IF_HTTP_EXTENSION~HANDLE_REQUEST.

*************************************************************
" VARIABLES
*************************************************************
DATA: LO_REST           TYPE REF TO ZIF_REST.
DATA: LV_REASON         TYPE STRING.
DATA: LO_INVALID_METHOD TYPE REF TO CX_ROOT.

**************************************************************
" GET THE CLASS WE WANT TO EXECUTE
**************************************************************
TRY.

LO_REST ?= GET_REST( IO_SERVER = SERVER ).

**************************************************************
" EXECUTE THE CLASS
**************************************************************
LO_REST->HANDLE_REQUEST( ).

**************************************************************
" CATCH IF IT PRODUCES ERRORS
**************************************************************
CATCH CX_ROOT INTO LO_INVALID_METHOD.

LV_REASON = LO_INVALID_METHOD->GET_TEXT( ).
SERVER->RESPONSE->SET_STATUS( CODE = 400   " Bad Request
REASON = LV_REASON ).

ENDTRY.

ENDMETHOD.​

This method will first check what type of request we’re dealing with (GET, PUT, POST, … etc.).  It will then append the name to the base class name. So, if a GET request is executed, the name of the class it will execute is ‘ZCL_REST_TEST_GET’.

METHOD GET_REST.

************************************************************
" VARIABLES
************************************************************
DATA: LV_CLASSNAME            TYPE SEOCLSNAME.
DATA: LV_METHOD               TYPE STRING.
DATA: LV_MESSAGE              TYPE TEXT255.

************************************************************
" REQUEST TYPE (GET, POST, ... ETC) AND APPEND IT TO GET THE CLASS NAME
************************************************************
LV_METHOD = IO_SERVER->REQUEST->GET_HEADER_FIELD( '~request_method' ).

CONCATENATE 'ZCL_REST_TEST_' LV_METHOD INTO LV_CLASSNAME.

*************************************************************
" RETURN THE CLASS TO IF_HTTP_EXTENSION~HANDLE_REQUEST
*************************************************************
TRY.
CREATE OBJECT EO_REST
TYPE (LV_CLASSNAME)
EXPORTING
IO_REQUEST   = IO_SERVER->REQUEST
IO_RESPONSE  = IO_SERVER->RESPONSE.

**************************************************************
" CATCH ERRORS
**************************************************************
CATCH CX_SY_CREATE_OBJECT_ERROR.
LV_MESSAGE = 'Method ''&'' not supported'(001).
ENDTRY.

ENDMETHOD.

4. Creating the class for a GET Request


Go to ‘SE24’ and create a new class ‘ZCL_REST_TEST_GET’ and add interface ‘ZIF_REST’.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Your class will now have the first two methods below. Add two new methods: ‘GET_EQUIPMENTS’ and ‘CONSTRUCTOR’.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Add the following parameters to ‘GET_EQUIPMENTS’. This will pass the request and return the equipments we will retrieve.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Add the following parameters to ‘CONSTRUCTOR’. This will instantiate the class when called upon.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Open method ‘HANDLE_REQUEST’. This method will be executed from the handler class (‘ZCL_REST_TEST’).

It will first get the equipments which will be converted to a JSON String. The String will then be added as output of this method.

METHOD ZIF_REST~HANDLE_REQUEST.

*************************************************************
" VARIABLES
*************************************************************
DATA: LT_EQUIPMENTS TYPE ZTT_TEST_EQUI,
LV_WRITER     TYPE REF TO CL_SXML_STRING_WRITER,
LV_CDATA      TYPE XSTRING,
LO_EX         TYPE REF TO CX_ROOT.

**************************************************************
" GET EQUIPMENTS
**************************************************************
TRY.

LT_EQUIPMENTS = GET_EQUIPMENTS( ME->ZIF_REST~REQUEST ).

**************************************************************
" CONVERT EQUIPMENTS TO JSON
**************************************************************
LV_WRITER = CL_SXML_STRING_WRITER=>CREATE( TYPE = IF_SXML=>CO_XT_JSON ).

CALL TRANSFORMATION ID SOURCE ARRAY =  LT_EQUIPMENTS RESULT XML LV_WRITER.

LV_CDATA = LV_WRITER->GET_OUTPUT( ).

*************************************************************
" ADD THE JSON EQUIPMENTS TO THE RESPONSE
*************************************************************
ME->ZIF_REST~RESPONSE->SET_DATA( DATA = LV_CDATA ).

CATCH CX_ROOT.
ENDTRY.
ENDMETHOD.

Now open method ‘SET_RESPONSE’ and add following code. This method will be executed when ‘HANDLE_REQUEST’ has finished. It will return the data as a String.

METHOD ZIF_REST~SET_RESPONSE.

CALL METHOD ME->ZIF_REST~RESPONSE->SET_DATA
EXPORTING
DATA = IS_DATA
*       offset             = 0
*       length             = -1
*       vscan_scan_always  = IF_HTTP_ENTITY=>CO_CONTENT_CHECK_PROFILE
*       virus_scan_profile = '/SIHTTP/HTTP_DOWNLOAD'
.
ENDMETHOD.

Now open method ‘CONSTRUCTOR’ and add following code. This method will instantiate the request and response when the class is called.

METHOD CONSTRUCTOR.

ME->ZIF_REST~RESPONSE = IO_RESPONSE.
ME->ZIF_REST~REQUEST = IO_REQUEST.

ENDMETHOD.

Now open method ‘GET_EQUIPMENTS’. This method will select an equipment which number is equals to the header parameter.

METHOD GET_EQUIPMENTS.

***************************************************************
" VARIABLES
***************************************************************
DATA: LT_HEADER_PARAMS TYPE TIHTTPNVP.

DATA: RETURN_VALUE TYPE CHAR200.
DATA: P_EQUNR      TYPE EQUNR.

**************************************************************
" GET HEADER PARAMETERS FROM URL
**************************************************************
IO_REQUEST->GET_FORM_FIELDS(
CHANGING
FIELDS = LT_HEADER_PARAMS ).

**************************************************************
" GET HEADER PARAMETER EQUIPMENT NUMBER
**************************************************************
LOOP AT LT_HEADER_PARAMS INTO DATA(LS_HEADER_PARAM) WHERE NAME EQ 'equnr'.
RETURN_VALUE = LS_HEADER_PARAM-VALUE.
ENDLOOP.

P_EQUNR = RETURN_VALUE.
UNPACK P_EQUNR TO P_EQUNR.
CLEAR: RETURN_VALUE.

**************************************************************
" GET EQUIPMENTS SELECT
**************************************************************
SELECT EQUI~EQUNR, EQKT~EQKTX
FROM EQUI AS EQUI
LEFT OUTER JOIN EQKT AS EQKT ON EQKT~EQUNR EQ EQUI~EQUNR
INTO TABLE @ET_EQUIPMENTS
WHERE EQUI~EQUNR EQ @P_EQUNR
AND EQKT~SPRAS EQ 'E'.

ENDMETHOD.

5. Creating the class for a POST Request


Go to ‘SE24’ and create a new class ‘ZCL_REST_TEST_POST’ and add interface ‘ZIF_REST’.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Your class will now have the first two methods below. Add a new method: ‘CONSTRUCTOR’.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Add the following parameters to ‘CONSTRUCTOR’. This will instantiate the class when called upon.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Open method ‘HANDLE_REQUEST’. This method will be executed from the handler class (‘ZCL_REST_TEST’). It will use the data that was added as the body of the POST request. Add the data as JSON.

METHOD ZIF_REST~HANDLE_REQUEST.

***************************************************************
" TYPES
***************************************************************
TYPES: BEGIN OF TYPE_FILE,
EQUNR    TYPE STRING,
EQKTX    TYPE STRING,
END OF TYPE_FILE.

****************************************************************
" VARIABLES AND OBJECTS
****************************************************************
DATA: LS_FILE               TYPE TYPE_FILE.
DATA: LT_FILES              TYPE TABLE OF TYPE_FILE.

DATA: LR_JSON_DESERIALIZER  TYPE REF TO CL_TREX_JSON_DESERIALIZER.
DATA: LV_REQUEST_JSON_BODY  TYPE STRING.
DATA: LV_WRITE              TYPE REF TO CL_SXML_STRING_WRITER.
DATA: LV_CDATA              TYPE XSTRING.

CREATE OBJECT LR_JSON_DESERIALIZER.

*************************************************************
" GET JSON DATA AND CONVERT TO ABAP DATA
*************************************************************
LV_REQUEST_JSON_BODY = ME->ZIF_REST~REQUEST->GET_CDATA( ).

LR_JSON_DESERIALIZER->DESERIALIZE(
EXPORTING
JSON = LV_REQUEST_JSON_BODY
IMPORTING
ABAP = LS_FILE ).

APPEND LS_FILE TO LT_FILES.

************************************************************
" CREATE OBJECT
************************************************************
"DO WHATEVER YOU NEED TO DO HERE  WITH THE DATA !!!

***********************************************************
" CONVERT INPUT TO JSON STRING
***********************************************************
LV_WRITE = CL_SXML_STRING_WRITER=>CREATE( TYPE = IF_SXML=>CO_XT_JSON ).
CALL TRANSFORMATION ID SOURCE ARRAY = LT_FILES RESULT XML LV_WRITE.
LV_CDATA = LV_WRITE->GET_OUTPUT( ).

************************************************************
" RETURN CREATED OBJECT AS RESPONSE (CONVENTION)
************************************************************
ME->ZIF_REST~RESPONSE->SET_DATA( DATA = LV_CDATA ).

ENDMETHOD.

Now open method ‘SET_RESPONSE’ and add following code. This method will be executed when ‘HANDLE_REQUEST’ has finished. It will return the data as a String.

METHOD ZIF_REST~SET_RESPONSE.

CALL METHOD ME->ZIF_REST~RESPONSE->SET_DATA
EXPORTING
DATA = IS_DATA
*       offset             = 0
*       length             = -1
*       vscan_scan_always  = IF_HTTP_ENTITY=>CO_CONTENT_CHECK_PROFILE
*       virus_scan_profile = '/SIHTTP/HTTP_DOWNLOAD'
.
ENDMETHOD.

Now open method ‘CONSTRUCTOR’ and add following code. This method will instantiate the request and response when the class is called.

METHOD CONSTRUCTOR.

ME->ZIF_REST~RESPONSE = IO_RESPONSE.
ME->ZIF_REST~REQUEST = IO_REQUEST.

ENDMETHOD.

6.  Creating a node in transaction SICF


Go to transaction ‘SICF’ and find a fitting node to which we can append a new one. In this case, we’ll opt for the already existing ‘ZREST’ node. Right click the node and add a new sub-element. We’ll name this node .

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Add a fittting description for the service node.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Navigate to the ‘Hander List’ tab and add the handler we created (‘ZCL_REST_TEST’).

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Make sure you save the service properly.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Go back to the node list and right click the node you created and click ‘Activate service’.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Click one of the two following buttons to active the node/service.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

7. Testing the GET service


Open Postman or something else to test web services.  Add the correct URL and authorization and press ‘SEND’.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

This will return an array with data. In this case only the equipment where the equipment number matches.

8. Testing the POST service


Open Postman or something else to test web services.  Add the correct URL and authorizations.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

Add the JSON body to the request and press ‘SEND’.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

You’ll get the posted object as result.

ABAP Development, NW ABAP Web Services, SAP NetWeaver, SAP ABAP Study Materials

That’s all there is to it. Thank you for reading and if there is any feedback or comments at all, you should definitely let me know since this is the first blog I’ve ever written.

No comments:

Post a Comment