Application Development and Automation Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
k_sood
Active Participant
38,129
 

In this Blog, I would like to present some code snippets, which could help others in order to consume Token based REST APIs in ABAP.

 

Obtaining the relevant details in order to get the Token

In order to get the Token, details like Application ID, Application Secret, Client ID and the Token Endpoint must be provided by the Provider.

Example how these details looks like is as follows:


Application ID, Client ID and Secret are simply data strings and the Token Endpoint is a URL.

Code Snippet in order to get a Token

The definition of which header parameters are needed in order to successfully call the Token Endpoint has to be provided by the API Provider.
METHOD get_token.
DATA: lo_http_token TYPE REF TO if_http_client,
l_response_token TYPE string.
DATA: l_status_code TYPE i.
DATA: lv_bas64enc TYPE string.
DATA: lv_url_token TYPE string,
lv_client_id TYPE string.
DATA: lo_root TYPE REF TO cx_root.

TRY.
*Url to access token
lv_url_token = IS_API_CREDENTI-token_endpoint. "Token Endpoint

* create http client Object
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = lv_url_token
IMPORTING
client = lo_http_token
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
* MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
* WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
*Close the client in case of Error
lo_http_token->close( ).
ENDIF.

* Set Method POST
IF lo_http_token IS BOUND.
lo_http_token->request->set_method( if_http_entity=>co_request_method_post ).
ENDIF.

*Set header parameter
*Convert string to base64
CONCATENATE IS_API_CREDENTI-APPLICATION_ID ':' IS_API_CREDENTI-APPLICATION_SEC INTO lv_bas64enc .



cl_http_utility=>encode_base64( EXPORTING
unencoded = lv_bas64enc
RECEIVING
encoded = lv_bas64enc ).

CONCATENATE 'Basic ' lv_bas64enc INTO lv_bas64enc RESPECTING BLANKS.

lo_http_token->request->set_header_field(
EXPORTING
name = 'Authorization'
value = lv_bas64enc
).

lo_http_token->request->set_header_field(
EXPORTING
name = 'Content-Type'
value = 'application/x-www-form-urlencoded'
).
lo_http_token->request->set_header_field(
EXPORTING
name = 'Accept'
value = 'application/json'
).
*Set all the form parameters
lo_http_token->request->set_form_field(
EXPORTING
name = 'grant_type'
value = 'client_credentials'
).

lo_http_token->request->set_form_field(
EXPORTING
name = 'scope'
value = 'client'
).


lv_client_id = IS_API_CREDENTI-client_id.
lo_http_token->request->set_form_field(
EXPORTING
name = 'client_id'
value = lv_client_id
).

* Turn off logon popup. detect authentication errors.
lo_http_token->propertytype_logon_popup = 0.

* Send / Receive Token Request
CALL METHOD lo_http_token->send
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
http_invalid_timeout = 4
OTHERS = 5.
IF sy-subrc <> 0.
* MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
* WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.

CALL METHOD lo_http_token->receive
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
OTHERS = 4.
IF sy-subrc <> 0.
* MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
* WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.

CALL METHOD lo_http_token->response->get_status
IMPORTING
code = l_status_code.

*Json response needs to be converted to abap readable format
CALL METHOD lo_http_token->response->get_cdata
RECEIVING
data = l_response_token.


/ui2/cl_json=>deserialize(
EXPORTING
json = l_response_token
CHANGING
data = is_token "Token will be stored in the instance structure, for retrieval in other methods.
).

lo_http_token->close( ).
CATCH cx_root INTO lo_root.
ENDTRY.
ENDMETHOD.

Data is_token is of the following type
    BEGIN OF ts_token,
token_type TYPE string,
access_token TYPE string,
expires_in TYPE string,
END OF ts_token .

 

Calling an API with PUT operation using the Obtained token including Error Handling

In the following code, An API is called using the Token obtained above in order to write some data on the API Provider side. Various return status codes which could come as return have also been processed.

Details of the Parameters which needs to be provided in order to make a call has to come from the API provider, Also the details about the structure of the error data has to come from the API provider.
METHOD put_employee_call.
DATA: lv_url_api TYPE string.
DATA: lo_http_put_empl TYPE REF TO if_http_client.

DATA: lo_root TYPE REF TO cx_root.

DATA: lv_access_token TYPE string.
DATA: l_response_put TYPE string.

DATA: l_status_code TYPE i.
DATA: ls_mitarbeiter_put_resp_422 TYPE ts_put_resp_unprocessable,
ls_mitarbeiter_put_resp_400_4 TYPE ts_put_resp_400_4.

DATA: ls_errors_422 TYPE ts_put_errors,
ls_msg TYPE bal_s_msg,
lv_text TYPE char200,
ls_emp_put_resp_200_201 TYPE ts_put.

TRY.


lv_url_api = is_api_credenti-api_endpoint_new .

*Create http client Object
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = lv_url_api
IMPORTING
client = lo_http_put_empl
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
* MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
* WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
*Close the client in case of Error
lo_http_put_empl->close( ).
ENDIF.
*Set Method POST
IF lo_http_put_empl IS BOUND.
lo_http_put_empl->request->set_method( 'PUT' ).
ENDIF.

*Set Header fields
lo_http_put_empl->request->set_header_field(
EXPORTING
name = 'Accept'
value = 'application/json'
).

lo_http_put_empl->request->set_header_field(
EXPORTING
name = 'Content-Type'
value = 'application/json'
).

CONCATENATE is_token-token_type is_token-access_token INTO lv_access_token SEPARATED BY space.

lo_http_put_empl->request->set_header_field(
EXPORTING
name = 'Authorization'
value = lv_access_token
).
*Set body Parameter
lo_http_put_empl->request->append_cdata( data = iv_empl_json ).
* Turn off logon popup. detect authentication errors.
lo_http_put_empl->propertytype_logon_popup = 0.

*Send / Receive PUT Request
CALL METHOD lo_http_put_empl->send
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
http_invalid_timeout = 4
OTHERS = 5.
IF sy-subrc <> 0.
* MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
* WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.

CALL METHOD lo_http_put_empl->receive
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
OTHERS = 4.
IF sy-subrc <> 0.
* MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
* WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.

*Get status code
CALL METHOD lo_http_put_empl->response->get_status
IMPORTING
code = l_status_code.

*Obtain Json response
CALL METHOD lo_http_put_empl->response->get_cdata
RECEIVING
data = l_response_put.

*deserializing json response
CASE l_status_code.
WHEN '422' . " Unprocessable Entry
/ui2/cl_json=>deserialize(
EXPORTING
json = l_response_put
CHANGING
data = ls_mitarbeiter_put_resp_422
).
*Add log for every Error Entry
LOOP AT ls_mitarbeiter_put_resp_422-errors INTO ls_errors_422.
CONCATENATE ls_errors_422-field ls_errors_422-code ls_errors_422-message INTO lv_text SEPARATED BY space.
me->return_log_variables( EXPORTING iv_text = lv_text CHANGING cs_msg = ls_msg ).
ls_msg-msgty = 'E'.
ls_msg-msgid = const_freetext_msgid.
ls_msg-msgno = const_freetext_msgno.
me->add_log_record( is_msg = ls_msg ).
CLEAR: ls_msg,ls_errors_422,lv_text.
ENDLOOP.

WHEN '400' OR '404'.
/ui2/cl_json=>deserialize(
EXPORTING
json = l_response_put
CHANGING
data = ls_mitarbeiter_put_resp_400_4
).
*Add one log Entry for 400 or 404
CONCATENATE ls_mitarbeiter_put_resp_400_4-message ls_mitarbeiter_put_resp_400_4-code INTO lv_text SEPARATED BY space.
me->return_log_variables( EXPORTING iv_text = lv_text CHANGING cs_msg = ls_msg ).
ls_msg-msgty = 'E'.
ls_msg-msgid = const_freetext_msgid.
ls_msg-msgno = const_freetext_msgno.
me->add_log_record( is_msg = ls_msg ).
CLEAR: ls_msg,lv_text.

*Add one Success entry for Update
WHEN '200'.
/ui2/cl_json=>deserialize(
EXPORTING
json = l_response_put
CHANGING
data = ls_emp_put_resp_200_201
).

CONCATENATE ls_emp_put_resp_200_201-external_id TEXT-002 INTO lv_text SEPARATED BY space.
me->return_log_variables( EXPORTING iv_text = lv_text CHANGING cs_msg = ls_msg ).
ls_msg-msgty = 'S'.
ls_msg-msgid = const_freetext_msgid.
ls_msg-msgno = const_freetext_msgno.
me->add_log_record( is_msg = ls_msg ).
CLEAR: ls_msg,lv_text.

*Add one Success entry for Creation
WHEN '201'.
/ui2/cl_json=>deserialize(
EXPORTING
json = l_response_put
CHANGING
data = ls_emp_put_resp_200_201
).
CONCATENATE ls_emp_put_resp_200_201-external_id TEXT-003 INTO lv_text SEPARATED BY space.
me->return_log_variables( EXPORTING iv_text = lv_text CHANGING cs_msg = ls_msg ).
ls_msg-msgty = 'S'.
ls_msg-msgid = const_freetext_msgid.
ls_msg-msgno = const_freetext_msgno.
me->add_log_record( is_msg = ls_msg ).
CLEAR: ls_msg,lv_text.
ENDCASE.
lo_http_put_empl->close( ).
CATCH cx_root INTO lo_root.
ENDTRY.
ENDMETHOD.

 

Thanks

Ketan

 

 
18 Comments
Dominik_Tylczynski
SAP Champion
SAP Champion
0 Kudos
Nice one!
k_sood
Active Participant
0 Kudos
Thanks Dominik.
JMoutreux
Participant
0 Kudos
Hello Ketan,

it is possible to have complete declaration part ?

 

and the service you use it's free one ?

 

thanks
k_sood
Active Participant
0 Kudos
Hi Jerome,

Its not a Free API.

Can you Specify which declaration part you need ?

Thanks
JMoutreux
Participant
Hello the declarations mean :
METHOD get_token

parameter
IS_API_CREDENTI

 
METHOD put_employee_call.

parameter
is_api_credenti

type
DATA: ls_mitarbeiter_put_resp_422   TYPE ts_put_resp_unprocessable,
ls_mitarbeiter_put_resp_400_4 TYPE ts_put_resp_400_4.

DATA: ls_errors_422 TYPE ts_put_errors,
ls_msg TYPE bal_s_msg,
lv_text TYPE char200,
ls_emp_put_resp_200_201 TYPE ts_put.

only Bal_s_msg and char200 is know.

 

method
me->add_log_record

me->return_log_variables

or if more simple send the complete code of class ?

 

I try to reproduce the class for a POC to test if Oauth V2  is possible on a system with basis 702 .
k_sood
Active Participant
0 Kudos
Everything you are asking for is Application dependent. You need to look for a Solution to your Specific problem.

 

 

 

 

 

 

 
MdZohaibAkhter
Explorer
0 Kudos

Hello,

What is the method to pass body in JSON format to the request?

Thanks

nitish_chawla2
Participant
0 Kudos

@k_sood Thanks for the detailed approach. You covered both get and post 🙂

I have a query here. Will calling an external API requires any port opening/ any security/basis setting or above program will be sufficient?

I understand that above api is a public API. My project had a requirement to fetch data from a paid private API.

Thanks in advance.

k_sood
Active Participant
0 Kudos

Hello @MdZohaibAkhter 

With the following Method you have to pass the Body.

*Set body Parameter
        lo_http_put_empl->request->append_cdata( data = iv_empl_json ).

BR,

Ketan

k_sood
Active Participant
0 Kudos

Hello @nitish_chawla2 ,

In this Scenario I did not need anything else. Best way would be to call the API through Postman, If that works without anything else, then from SAP also it should work only with the above Coding.

And the API, I have used in this Scenario, is a Paid one.

BR,

Ketan

pawan_rai
Participant
0 Kudos

Hi @k_sood ,

I have a requirement where I have to connect the SAP to Microsoft SharePoint for sending, receiving and deleting document

As mentioned in this blog start phase, Application ID, Application Secret, Client ID and Token Endpoint is mentioned. I have been currently only given Online URL which I suppose would be the token Endpoint as per the blog. 

So, my query is just like the data is passed in set header field in the blog, similarly I need to pass the rest pending data like Application ID, Application secret and Client ID??

If you have any blog which is based on similar requirement it would be really helpful to me.

Thanks

Pawan

 

Sandra_Rossi
Active Contributor
0 Kudos

@pawan_rai It's exactly the same HTTP/S request as the one you pass through Postman, SOAPUI or whatever software. If you don't have Postman, it's time to install and use it.

pawan_rai
Participant
0 Kudos

Thanks, Sandra for a prompt reply.

Yes, as u have correctly mentioned I will pass this data to postman to test whether it is working correctly or not?

My requirement is to give an option of Create attachment with SharePoint in GOS toolbar which I have already achieved. Once the user selects this option from any transaction suppose MM02, Microsoft SharePoint should open, inside that there would be folder, subfolder. User can perform either attach document from SharePoint or delete the attachment or retrieve document.

So, my query is I would be requiring the details of API for all operations like Create, Delete etc. from SharePoint end? Once given, to which method I need to pass this data inside my code? Is it the header details method?

Thanks in advance.

Regards

Pawan

Sandra_Rossi
Active Contributor
0 Kudos

@pawan_rai For Microsoft SharePoint questions, I think that the best place to ask in in the Microsoft SharePoint forums.

Sriram961
Explorer
0 Kudos

Hi @k_sood ,

Thank you for sharing detailed blog. With your code I am able to generate access token of External API.

But the challenge is ,in the code shared by you Client secret is hardcoded. Instead of hardcoding is it possible to use Oauth Profile as our client secret gets updated once in every 6 months.

Thanks

Deepthi

k_sood
Active Participant
0 Kudos

Hi @Sriram961 

You have to look at this from the API Provider side, You have to provide it whatver it requires to Authenticate your Request.

In the Scenario explained in this blog, Client secret is not hard coded, it is stored in a Customizing table for every system.

Changing client secret every six months is certainly not an issue.

Br,

Ketan

Sriram961
Explorer
0 Kudos

Hi @k_sood ,

Instead of storing client secret can we use Oauth profile.

If you have used oauth profile kindly share the logic to get Token using oauth profile .

Thanks

@Sriram961

k_sood
Active Participant
0 Kudos

@Sriram961 

I dont have it. Start a new Post in the community with your Requirement and all the details you have, including, what all you have tried so far.