Technical Articles
USING API INSTEAD OF BAPI
Introduction
The SAP system is developing and changing day by day. Sometimes keeping track of changes can be quite challenging. Perhaps the best part of this profession is that it constantly compels you to learn new things. SAP API HUB offers us many services and it is possible to find these services on the on-premise system. In this blog post, I will try to show you how to create BP using the API on-premise system. Even if this article was written only for BP; I think it will give a general idea about other services such as purchase order creation, sales order creation, etc.
STEP-BY-STEP IMPLEMENTATION
- In the SAP system, call the / IWFND / MAINT_SERVICE transaction code and click the ADD SERVICE button.
Add Service
- After giving the System Alias and External Service name, click the “ADD SELECTED SERVICE” button.
Add Selected Services
- Continue by giving your technical service name and desired package on the pop-up screen.
Technical Configuration
- You will get a success message when everything goes well. If you wish, you can try the service by clicking the “SAP GATEWAY CLIENT” button or using a 3rd party software such as Postman.
Call Gateway Client
Try out the service
- The part until now was only to activate the service. Now is the time to get our hands dirty. For this, we will create an ABAP program and a class. Our program will consist of username, password, and URL information at the selection screen. Sample URL: http://<YOUR_HOST_HERE>:<YOUR_PORT_HERE>/sap /opu/room/sap/ api_business_partner / A_BusinessPartner? Sap-client = 100
Selection Screen
- Abap class will contain two methods, the first method will receive CSRF tokens and cookies, and the second method will send a POST request.
REPORT zbp_api.
SELECTION-SCREEN BEGIN OF BLOCK bl0 WITH FRAME TITLE TEXT-t00.
SELECTION-SCREEN BEGIN OF BLOCK bl1 WITH FRAME TITLE TEXT-t01.
PARAMETERS: p_unam TYPE string LOWER CASE OBLIGATORY,
p_pass TYPE string LOWER CASE OBLIGATORY,
p_url TYPE string LOWER CASE OBLIGATORY.
SELECTION-SCREEN END OF BLOCK bl1.
SELECTION-SCREEN END OF BLOCK Bl0.
AT SELECTION-SCREEN OUTPUT.
"have a little decency and hide password field
LOOP AT SCREEN.
IF screen-name = 'P_PASS'.
screen-invisible = 1.
MODIFY SCREEN.
ENDIF.
ENDLOOP.
START-OF-SELECTION.
CLASS lcl_odata_tool DEFINITION.
PUBLIC SECTION.
CLASS-METHODS get_csrf_token_and_cookie
EXPORTING
!et_cookies TYPE tihttpcki
!ev_token TYPE string .
CLASS-METHODS create_opp
IMPORTING
!iv_token TYPE string
!it_cookies TYPE tihttpcki .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS lCL_ODATA_TOOL IMPLEMENTATION.
METHOD get_csrf_token_and_cookie.
DATA: lo_http_client TYPE REF TO if_http_client,
lv_status TYPE i,
lt_fields TYPE tihttpnvp,
lv_sysubrc TYPE sysubrc.
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = p_url
IMPORTING
client = lo_http_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4.
ASSERT sy-subrc = 0.
.....
.....
.....
ev_token = <field>-value.
lo_http_client->response->get_cookies( CHANGING cookies = et_cookies ).
lo_http_client->close( ).
ENDMETHOD.
METHOD create_opp.
DATA:lo_http_client TYPE REF TO if_http_client,
lv_sysubrc TYPE sysubrc,
lv_body TYPE string,
ls_bp TYPE zapi_s_bsnsp,
lt_adress TYPE TABLE OF zapi_s_adress,
lr_out TYPE REF TO data.
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = p_url
IMPORTING
client = lo_http_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4.
......
......
......
cl_demo_output=>write_json( lv_json ).
cl_demo_output=>display( ).
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
DATA(lo_class) = NEW lcl_odata_tool( ).
lo_class->get_csrf_token_and_cookie(
IMPORTING
et_cookies = DATA(et_cookies)
ev_token = DATA(ev_token)
).
lo_class->create_opp(
EXPORTING
iv_token = ev_token
it_cookies = et_cookies
).
- After successfully created BP you can call BP transaction and observe your newly created BP record.
Newly Created BP
If you wish, you can access all the codes on the GITHUB page to review. I shortened codes with dots for don’t cover so much place. I have created many structures in the system, you can pull your own system with the help of the ABAPGIT program. You can see that I start with underscores for some fields in the structure I created it with that way because when I use “/ ui2 / cl_json => serialize” I want to capitalize the field after each underscore. Since Abap does not allow more than 30 characters for field names, I changed some names using REPLACE ALL OCCURRENCES OF. Make sure that the fields assigned as Hard Code, such as BusinessPartnerGrouping, CustomerAccountGroup, are customized in the same way on your system, or change these fields to customization in your system or comment them completely.
Conclusion
The purpose of my writing this blog post is due to that we mostly have to reinvent the wheel during some integrations. As in the business partner example, we can use some APIs available in the system during some integrations. When we use Bapi, we often do not know which field matches which table field (you need to look at domain), but when we use API, all fields will be brought in front of us with a simple get request. After creating a manual sample, we can simply make all field matches. Or we can use the ready service instead of coding a new service when we created a front-end program that creates a record. Moreover, when we need additional fields, we can easily use the additional fields after we added them.
REFERENCES:
https://blogs.sap.com/2020/06/11/how-to-find-an-api-on-sap-s-4hana-op-en/
https://blogs.sap.com/2017/02/28/api-business-hub-abap-code-snippet-for-apis/
Sorry, I'm confused: what is the potential use case of such design? Instead of using a BAPI that runs within the same SAP application you're taking a long detour over HTTP to a service. Why? Just because "we often do not know which field matches which table field"? They usually have the same data type, so really not that hard to figure out. ABAPers have been doing this for decades.
Don't mean to hate on your blog and this could be an example of how to do an HTTP call to somewhere from ABAP. (Although there are already blogs like this and probably not a good idea to have credentials entered on a selection screen.) But I'm questioning the specific design and justification for it.
Also, this blog post leaves a lot of information behind the scenes. I know it, you know it, but I suspect many readers could be confused. For example, where did you get the API name for the service? How did you come up with the code that you're sharing?
Thank you.
Hi,
I am aware that I am taking a long detour. I am not saying that anybody must use API, I was just for showing another way of doing something. I always came across with questions about how can I use SAP's APIs and about tokens. In my opinion, this blog also includes how to use them.Β I agree with you, I would prefer to use BAPI in ABAP.
"Just because "we often do not know which field matches which table field"? They usually have the same data type, so really not that hard to figure out.". when you look at the table field and further characteristics tab , you are gonna see the BAPI's matching field such as MATNR is MATERIAL. But it is not easy to understand for all abapers, because I think abbreviations come from German but descriptions come from English. You should count that all of us don't know German and life is too short... πΒ Let,s look at Sales order tables(VBAK-VBRK-LIKP) everything is VBELN there but has different data elements.
I really find useful your comments, I really appreciate you take your time for comments.
Selection screen was just for someone who wants to try it out after pulling it from Github.
"you know it, but I suspect many readers could be confused. For example, where did you get the API name for the service?". I gave a reference for this and didn't want to keep the blog post so long :).
I still think that it can be a better way to use SAP's own APIs for 3rd party integration than recoding for it. I think experienced Abaper will observe thatΒ Odata services are not only for SAPUI5 developments.
Best Regards.
Thanks for a reply. You might want to move the link for finding API closer to the top, otherwise it's not apparent to the readers.
Maybe it's just me but I don't really know German either and I started working with SAP long before these APIs existed and we somehow survived. Usually the users would point on the screen that they want to update "this field", you hit F1, get the field type and then simply search in BAPI structure. Try doing that with API. π
More importantly though, as Sandra noted, the code doesn't actually show how API is accessed via ABAP.
I don't deny that F1 is helpful but as you know developer likes meaningful names for clean code. In my opinion, shortened names bring a lot of confusion as well.
I am sending a basic HTTP POST request from ABAP, I hadn't thought that it will confuse people so much.
Best Regards.
Yes, it is a POST request but the most important part of the code seems to be hiding behind the dots. The blog title is "using API" but the code only covers the HTTP part, basically. If the title was "How to perform HTTP POST request", no one would say anything.
"Developer likes meaningful names" + "clean code" and then using names like ls_bp and lr_out in your own code? C'mon now. "Walk the walk". π
I'm afraid I'm part of the confused readers. Could you explain what code contains the OData service, I just see an empty one, and how the BP is created? Thank you. Except the OData "envelope", I don't see anything related to API or BAPI in your blog post.
Hi Sandra,
Would you please check the link. This is standard service or odata service whatever you named it π I assumed that people who regarded this blog know that how to use BAPIs and how to create BP using BAPIs.
Now I understand that the "External Service name" is the name of an existing API. Thank you for clarifying π