Friday, 10 February 2023

How to consume RESTful Cloud API from SAP with JSON request – MS Dynamics

Development Requirement 


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

SAP ABAP, SAP ABAP Career, SAP ABAP Skills, SAP ABAP Job, SAP ABAP Tutorial and Materials

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

SAP ABAP, SAP ABAP Career, SAP ABAP Skills, SAP ABAP Job, SAP ABAP Tutorial and Materials

SAP ABAP, SAP ABAP Career, SAP ABAP Skills, SAP ABAP Job, SAP ABAP Tutorial and Materials

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 

SAP ABAP, SAP ABAP Career, SAP ABAP Skills, SAP ABAP Job, SAP ABAP Tutorial and Materials

No comments:

Post a Comment