Switching from a conventional middleware to direct consumption of a RESTful API in Azure Cloud requires me to design and build a new SAP program .

 

Business scenario 

SAP Invoices are to be sent out to Microsoft Dynamics AX Cloud to create local invoices in AX. The invoices from SAP need to be stored in a staging storage in MSDAX before being converted to the local invoices.

 

Technical configurations – Prerequisite 

  1. Obviously, you need url of API endpoint
  2. Open Firewall – add the target endpoint of API to White List in your network
  3. Configuration of Certificate of API endpoint on Azure in STRUST – SAP Oss note 2333326
  4. API key and value of API (Apps) on Azure – Need to get them issued from the target system

How to get an open SSL certificate – > Please refer to SAP OSS Note  2333326 – Tutorial – “Establishing trust between SSL client and SSL server on AS ABAP

 

SAP development  

Define a deep structure and an internal table, Sub field “items” is refer to a Table Type for items

 

Fill in data to the internal table with header & line items data

 

Json serialization 

Simple you can use  /ui2/cl_json=>serialize( ) but my case I need to tag document numbers with json request to save the return log. I used /UI2/CL_JSON_SERIALIZER to give a little bit tweak

Define GR_JSON_SERIALIZER  Type Ref To /UI2/CL_JSON_SERIALIZER

METHOD conv_jsonformat.

FREE gt_str_json.                             <- table type of  ‘z???_json’  
DATA ls_rv_json TYPE z???_json.    <- Document number + Json string 

    FREE gt_str_json.
    DATA ls_rv_json TYPE zvim_s_docid_json.

    LOOP AT gt_str_abap ASSIGNING FIELD-SYMBOL(<fs_l_abap_str>).
      GET REFERENCE OF <fs_l_abap_str> INTO DATA(lref_table).
      DATA(lv_json_str) = gr_json_serializer->/ui2/if_serialize~serialize( lref_table  ).
      CONCATENATE  '{"' 'INVOICES' '"  : '  '['    lv_json_str ']'  '}'  INTO ls_rv_json-json .
      ls_rv_json-docid = <fs_l_abap_str>-docid.
      APPEND ls_rv_json TO gt_str_json.
    ENDLOOP.

 

Open HTTP client 
    cl_http_client=>create_by_url(
         EXPORTING   url = url_path "Endpoint URL 
         IMPORTING   client = DATA(lr_client)
         EXCEPTIONS  argument_not_found = 1
                     plugin_not_active  = 2
                     internal_error     = 3
                     OTHERS             = 4  ).

 

Add API key and value into the header of json request 

EXPORTING    name  = ‘????key???’     <- The name of API key 
                         value   = ‘value?????’ ).   <- The value of the API key 

* Pass Credential
    lr_client->request->set_header_field(
        EXPORTING name  = apikey_pair-name
                  value = apikey_pair-value ).

 

Define Json format and method type 'Post' in this case  
* Declare Json format
    lr_client->request->set_content_type( if_rest_media_type=>gc_appl_json ).
*POST
    lr_client->request->set_method( if_http_request=>co_request_method_post ).

 

Send request
* Send body
    LOOP AT gt_str_json ASSIGNING FIELD-SYMBOL(<fs_l_jsonbody>).
      lr_client->request->set_cdata( <fs_l_jsonbody>-json ).
*
* Send
      lr_client->send(    EXCEPTIONS  http_communication_failure = 1
                                http_invalid_state         = 2
                                http_processing_failed     = 3
                                http_invalid_timeout       = 4
                                OTHERS                     = 5 ).

      lr_client->receive( EXCEPTIONS
                                http_communication_failure = 1
                                http_invalid_state         = 2
                                http_processing_failed     = 3
                                OTHERS                     = 4 ).
      IF sy-subrc <> 0.
        lr_client->get_last_error( IMPORTING code    = DATA(lv_errcode)
                                             message = DATA(lv_errmesg) ).
*       RAISE EXCEPTION TYPE zcx_ax MESSAGE e000 WITH lv_errmesg lv_errcode .
*        ls_bapiret2-message =  |{lv_errmesg}| &&  |{lv_errmesg}|.
        ls_bapiret2-message = lv_errmesg && '  ' && lv_errmesg.
        ls_bapiret2-type = 'E'.
* Build
      ELSE.
        DATA(_rt_from_call) = lr_client->response->get_cdata( ).
*
        update_single_inv( <fs_l_jsonbody>-docid  ).
        ls_bapiret2-message = _rt_from_call.
        ls_bapiret2-type = 'S'.
      ENDIF.
      ls_bapiret2-message_v1 = <fs_l_jsonbody>-docid.
      APPEND ls_bapiret2 TO rt_messages.
      CLEAR  ls_bapiret2.
    ENDLOOP.

 

You can close HTTP client  CL_HTTP_CLIENT->CLOSE( ).  now 



body of Json request that used in the above code   

{
    "INVOICES": [
        {
            "DOCID": "00000?????",
            "ITEM_COUNT": "00002",
            "BUKRS": "7??",
            "XBLNR": "T??????9",
            "BLDAT": "????-??-??",
            "LIFNR": "0000?????",
            "CREDIT_MEMO": " ",
            "EBELN": null,
            "BKTXT": null,
            "SGTXT_HEADER": null,
            "GROSS_AMOUNT": 1100.00,
            "VAT_AMOUNT": 100.00,
            "DATE_CREATED": "????-??-??",
            "ITEMS": [
                {
                    "ITEMID": "00001",
                    "KOSTL": "000070?????",
                    "HKONT": "00000?????",
                    "PRCTR": null,
                    "SGTXT_ITEM": "LINE 1",
                    "MWSKZ": "P1",
                    "SHKZG": "S",
                    "WRBTR": 550.00,
                    "ZUONR": null
                },
                {
                    "ITEMID": "00002",
                    "KOSTL": "00007????",
                    "HKONT": "00000?????",
                    "PRCTR": null,
                    "SGTXT_ITEM": "LINE 2",
                    "MWSKZ": "P1",
                    "SHKZG": "S",
                    "WRBTR": 550.00,
                    "ZUONR": null
                }
            ]
        } 
    ]
}

 

Unit Test

MS Dynamics AX Cloud  

 

 

Conclusion

It’s quite simple and concise logics as you can see and not much efforts required to build ABAP code for Json interface. There is no doubt that many useful methods in ABAP class  CL_HTTP_CLIENT & /ui2/cl_json will help making your codes simpler and self-explained pattern.   

 

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x