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
- Obviously, you need url of API endpoint
- Open Firewall – add the target endpoint of API to White List in your network
- Configuration of Certificate of API endpoint on Azure in STRUST – SAP Oss note 2333326
- 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.