Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
136,018

Introduction


 

In this blog I would like to show the basics of OData service development with SAP Gateway when using code based service implementation as it is shown in the upcoming SAP CodeJam events about OData service development with SAP Gateway.
Though the recommended approach for OData service development in the most recent SAP NetWeaver releases is to use CDS views there are still a number of use cases where code based service implementation is a valid option.

  1. Your SAP backend system is based on a SAP NetWeaver release 7.31 or earlier

  2. Your system is based on SAP NetWeaver 7.40 or later but the business logic you want to re-use has been implemented in ABAP code

  3. It is not possible to implement your business logic in CDS views


 

As an example we will use a simple OData model based that consist out of SalesOrders and SalesOrderItems with the option to navigate from a SalesOrder to the correponding line items.

 

If you are more interested in using CDS views please have a look at my following post: OData service development with SAP Gateway using CDS via Referenced Data Sources

If you want to know how to annotate services using code based implemenation you can have a look at my following post:

https://blogs.sap.com/2017/04/21/how-to-add-annotations-to-an-odata-service-using-code-based-impleme...

Changes



  • 28.06.2016  Fix for ABAP code: Replaced
    lv_osql_where_clause = io_tech_request_context->get_osql_where_clause( ).
                     through
    lv_osql_where_clause = io_tech_request_context->get_osql_where_clause_convert().
    because otherwise the statement GET SalesOrderSet?$filter=(Customer eq '100000000') would not work because alpha conversion to '0100000000' would not take place.

  • 24.11.2016 Moved ABAP source code into source code controls

  • 21.04.2017 Added a link that explains how to add annotations to the service.

  • 21.02.2018 Added a hint to un-check the Filter checkbox in SE24


 

Prequisites


 

The examples shown in this blog are based on the latest SAP NetWeaver release 750so that we can compare the different implementation approaches

 

 

Creating a basic OData service


 

We will perform the following steps:

 

  • Use the SAP Gateway Service Builder to create a new project

  • Import a DDIC structures for SalesOrder to create the data model

  • Generate, register and test the OData service using the Gateway Client

  • Perform a first implementation of the GET_ENTITYSET method


 

Create a new Service Builder project


 

  • Start the Gateway Service Builder by running transaction SEGW.

  • Click on the Create Project button

  • Provide the following information:


Project: ZE2E100_XX


Description: ZE2E100_XX


Service Package: $TMP


Note: Replace XX with your session-id / group number.


 



 

 

 

  • Press Continue

  • Press Save



Import a DDIC structures for SalesOrder


 

  • Right-click on Data Model and select Import --> DDIC Structure.


 




  • In the first step of the wizard provide:In the field Name, enter SalesOrder
    In the field ABAP Structure, enter SEPM_ISOE.
    Click
    Next.

  • In the second step of the wizard provide:Select the checkbox for SEPM_ISOE.
    Deselect the checkbox for MANDT,
    Click Next.

  • In the third screen of the wizardSelect the checkbox Is Key for the field SALESORDER.
    Click Finish.


  • Expand Folder Properties and examine the entity SalesOrder and the entity set SalesOrderSet.(For example the property names, the Edm Core Type values and the ABAP field names)

  • Press Save

  • Press the Check Project Consistency button.

  • Verify that no errors were found.

  • Press the Generate Runtime Objects button.Note: Using the Generate Runtime Objects button automatically saves the project.

  • Leave all values as defaulted and press Enter.





  • Choose Local Object in the Create Object Directory Entry popup.

  • Verify that the generation was successful.



 

Now you have created an (empty) service implementation in the SAP backend.

 

 

Register and Test the OData service using the Gateway client


 

  • Expand the node Service Maintenance and right-click on GW_HUB and select Register.





  • In the Add Service popup leave all values as defaulted and press the Local Object button to assign the artifacts to the $tmp package. Then press Enter to continue





  • Double-click on the GW_HUB entry under Service Maintenance. Verify that the registration status on the right-hand side is showing a green traffic light.




  • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.Alternatively click on the SAP Gateway Client button in the detail section.

  • Confirm the warning popup that warns you that you will be redirected to the selected system. Select Yes.

  • This opens up the SAP Gateway Client in a new screen. The URI of the service document is already defaulted.
    Press the Execute button.




  • As a result you get the service document of your OData service in the HTTP response window




  • Press the Button “Entity Sets” and select SalesOrderSet.




  • After pressing Execute button which executes the following URI
    /sap/opu/odata/SAP/ZE2E100_<XX>_SRV/SalesOrderSet
    you see an error message that indicates that the method SALESORDERSET_GET_ENTITYSET has not yet been implemented.




 

 

Provision the GET_ENTITYSET method of the service using ABAP code


 

  • Open the Service Builder Project again (if you have closed it)

  • Expand the node Service Implementation and expand SalesOrderSet.
    Now right-click on GetEntitySet(Query) and choose
    Go to ABAP Workbench.




  • Confirm the warning“Operation SALESORDERSET_GET_ENTITYSET has not yet been implemented”

  • Switch to edit mode, scroll down to the method SALESORDERSET_GET_ENTITYSET and make sure to select it.Click on the Redefine Method button.Make sure to have the check box Filter unchecked because otherwise only redefined method would be visible. So in the beginning the list would look empty.

  • Use Copy&Paste to copy the entire coding shown below into the salesorderset_get_entityset method. Please note: This is a new syntax for ABAP SQL.
    method SALESORDERSET_GET_ENTITYSET.

    select * from sepm_i_salesorder_e
    into corresponding fields of table @et_entityset.

    endmethod.








    • Info: The replaced coding selects data from the CDS view sepm_i_salesorder_e.The results are filled into the corresponding fields of the return structure et_entityset of the get-entityset method.
      This works out of the box since the structure SEPM_ISOE was used to create the entity type using DDIC import. This structure is the so called sqlViewName of the CDS view sepm_i_salesorder_e. The source code of the DDL source can be viewed using the report RUTDDLSSHOW.



  • Click on Activate.

  • Confirm the activation popup.

  • Navigate back to the Service Builder main screen using the green back button multiple times.

  • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.Alternatively click on the SAP Gateway Client button in the detail section.




  • This opens up the SAP Gateway Client in a new screen. The URI of the service document is already defaulted.
    Press the Button “Entity Sets” and select SalesOrderSet
    The request URI field will contain the following value:


/sap/opu/odata/SAP/ZE2E100_<XX>_SRV/SalesOrderSet

        (Replace <XX> by your group number.)


 

After pressing Execute button you see a list of sales orders.

 



 

  • You can retrieve the number of sales orders by adding “/$count” to the request URI/sap/opu/odata/SAP/ZE2E100_<XX>_SRV/SalesOrderSet/$countReplace <XX> by your group number and press Execute


 





Add support for $filter to your code


 

  • Open the Service Builder Project again

  • Expand the node Service Implementation and SalesOrderSet and choose the entry GetEntitySet (Query).
    Now right-click on GetEntitySet (Query) and choose
    Go to ABAP Workbench.




  • This time the ABAP editor will open the method salesorderset_get_entityset  immediately.
    Switch to the change mode and replace the code with the code shown below.
    The code retrieves the $filter statement as an osql statement for the where clause.
    The data is retrieved and inserted into the return table et_entityset.


 


 



  method SALESORDERSET_GET_ENTITYSET.

data: lv_osql_where_clause type string.
lv_osql_where_clause = io_tech_request_context->get_osql_where_clause( ).
select * from sepm_i_salesorder_e
into corresponding fields of table @et_entityset
where (lv_osql_where_clause).

endmethod.





  • Click on Activate.

  • Navigate back to the Service Builder main screen using the back button

  • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.Alternatively click on the SAP Gateway Client button in the detail section.

  • This opens up the SAP Gateway Client in a new screen. The URI of the service document is already defaulted.

  • Replace the URI with the following:

    /sap/opu/odata/SAP/ZE2E100_<XX>_SRV/SalesOrderSet?$filter=Grossamountintransaccurrency ge 100000&$select=Salesorder,Grossamountintransaccurrency,Transactioncurrency&$format=json

    Replace <XX> by your group number and press Execute

    This will deliver a list of four sales orders whose gross amount exceeds 100.000 Euro and will only show the sales order number and the gross amount.


     500000005
     500000030
     500000034
     500000045






 

Add support for additional query options to your code


 

 

  • Open the Service Builder Project again

  • Expand the node Service Implementation and right-click on SalesOrderSet and choose the entry GetEntitySet (Query).
    Now right-click on GetEntitySet (Query) and choose
    Go to ABAP Workbench.


 

  • This time the ABAP editor will open the method salesorderset_get_entityset immediately.

  • Switch to the edit mode.
    Replace the code with the code shown below.
    The code retrieves the values for $top and $skip and the $filter statement as an osql statement for the where clause.The data is retrieved and in the end it is checked whether $inlinecount is used (which is a default for SAPUI5)


 
  method SALESORDERSET_GET_ENTITYSET.

data: lv_osql_where_clause type string,
lv_top type i,
lv_skip type i,
lv_max_index type i,
n type i.
*- get number of records requested
lv_top = io_tech_request_context->get_top( ).
*- get number of lines that should be skipped
lv_skip = io_tech_request_context->get_skip( ).
*- value for maxrows must only be calculated if the request also contains a $top
if lv_top is not initial.
lv_max_index = lv_top + lv_skip.
endif.
lv_osql_where_clause = io_tech_request_context->get_osql_where_clause( ).

select * from sepm_i_salesorder_e
into corresponding fields of table @et_entityset
up to @lv_max_index rows
where (lv_osql_where_clause).
*- skipping entries specified by $skip
if lv_skip is not initial.
delete et_entityset to lv_skip.
endif.
*- Inlinecount - get the total numbers of entries that fit to the where clause
if io_tech_request_context->has_inlinecount( ) = abap_true.
select count(*) from sepm_i_salesorder_e where (lv_osql_where_clause) .
es_response_context-inlinecount = sy-dbcnt.
else.
clear es_response_context-inlinecount.
endif.


endmethod.


  • Click on Activate.

  • Navigate back to the Service Builder main screen using the back button  multiple times.

  • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.Alternatively click on the SAP Gateway Client button in the detail section.

  • This opens up the SAP Gateway Client in a new screen. The URI of the service document is already defaulted.

  • Replace the URI with the following:/sap/opu/odata/SAP/ZE2E100_<XX>_SRV/SalesOrderSet?$filter=Grossamountintransaccurrency ge 100000&$select=Salesorder,Grossamountintransaccurrency,Transactioncurrency&$top=2&$skip=1&$inlinecount=allpages&$format=jsonReplace <XX> by your group number and press Execute
    This will deliver a list of only 2 sales orders whose gross amount exceeds 100.000 EUR. The first sales order 500000005 is skipped and only the first 2 of the rest of the list (highlighted in bold) are shown.
    The inlinecount however shows that in total 40 sales orders would fit to the filter criteria.

    500000005
    500000030 <--
    500000034 <--
    500000045
    Please note: $skip, $top and $inlinecount are used for client side paging. SAPUI5 uses this to calculate how many pages one has to navigate through.


 



 

 

What is now left is the implementation of the GET_ENTITY method of the entity set SalesOrderSet and the modelling and implementation of the navigation between sales order header and the line items.

 

This will be described in the second part of this blog post OData service development with SAP Gateway - code-based service development - Part II because the editor refused to let me add any additional screen shots at this point :wink: .
29 Comments
TimMuchena
Participant
0 Kudos

Hi Andre

Thanks for sharing your Gateway knowledge. I am learning a lot from you.

Kind regards

former_member181883
Active Participant
0 Kudos

If like me, you find that when testing your service in the Gateway Client txn, you get a German error message popping up "HTTPIO_ERROR_CUSTOM_MYSAPSSO-Fehlermeldung beim Senden der Daten", then (as the message so clearly indicates?), this means the profile parameter for your ABAP system to control the creation and use of SSO2 logon tickets has not been configured correctly.

See André's other blog for details of how to fix this: http://scn.sap.com/community/gateway/blog/2015/11/26/sso-problem-with-the-sap-gateway-client-iwfndgw...


Chris W

Former Member

It is probably worth mentioning that Gateway doesn't support all the where clauses OSQL supports, e.g. I had to code support for Contains Pattern (CP).

joachimrees1
Active Contributor
0 Kudos

Thanks for sharing, André!

Do you actually recommend using SE24 to get the ABAP-Code in the generated classes?

Shouldn't we use eclipse for that?

(I'm currently trying to get to love eclipse, overcoming the "it's easier the old way (as I have been doing that for a long time -> Eclipse is something new)"-feeling.

That's why I always get a little insecure when seeing the traditional ABAP Workbench used in modern examples like yours.

best

Joachim

Andre_Fischer
Product and Topic Expert
Product and Topic Expert

you can use ABAP in Eclipse. I have described this in the following blog Using SEGW and ABAP in Eclipse. :smile:

joachimrees1
Active Contributor
0 Kudos

cool, thanks André!

former_member200889
Participant
0 Kudos

Hi Andre,

Thank for sharing, I am a beginner in fiori. I am learning how to develop fiori app.

I refer to your infomation, follow by implementation,

in step "Expand the node Service Maintenance and right-click on GW_HUB and select Register"

I can't see the GW_HUB, what is the reason?

Best regards,

Daniel

Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Daniel,

you have to configure it as described in step 3 of my document Quick Starter Configuration Guide - SAP Gateway .

Best Regards,

Andre

former_member200889
Participant
0 Kudos

Hi Andre,

Thanks for your reply.

I will go to implement refer document.

So,  after my configuration is complete, and then re-created the object, it will appear.

In addition, prior to implementation of the part, I still need to configure other settings?

Thanks for your guidance.

Best Regards,

Daniel

mike_reader3
Active Participant
0 Kudos

Samuli,

I was trying to use the OData canonical function 'contains' - which I assume would map to the CP you are referring to (in the ideal world) ... but as you say it is not supported.

I was thinking about combining startswith and endswith to achieve a similar result.

Thoughts?

Thanks, Mike

Former Member

It might work depending on your use case. In my case, I detect in the DPC_EXT class if SELOPT-SIGN = 'I', SELOPT-OPTION = 'EQ' and SELOPT-LOW contains '*' and if it does, I simply change SELOPT-OPTION to 'CP' before handing over for processing.

joachimrees1
Active Contributor
0 Kudos

André, as we just discussed:

select * from sepm_i_salesorder_e
into corresponding fields of table @et_entityset
up to @lv_max_index rows
where (lv_osql_where_clause).

"add ORDER BY here!!
*- skipping entries specified by $skip
if lv_skip is not initial.
delete et_entityset to lv_skip.
endif.


I think you have to add an "ODER BY" clause here (e.g. order by PRIMARY KEY) , in order to ensure that the results comming back from the select are sorted in the same way with every execution of the select statement!


best

Joachim


Edit: also see current discussion here: Re: ORDER BY in Custom-Code for HANA

Pavan_Golesar
Active Participant
0 Kudos
Fantastic update  Andre. 

Regards,
Pavan G 
0 Kudos
Perfect.

Good Job! 🙂
Former Member
0 Kudos
Hi Andre,

Very nice blog.

I have followed your steps, and achieved the result. Just one doubt, here we are importing a DDIC structure , say , VBAK table. Then we did some in the class in se24 and moved the contents to et_entityset table. Hence in such cases, our et_entityset is of the type of VBAK table.

What if I don't want to import a DDIC structure ?

I have done some code in my SE24 class, but i dont understand what should be the type of my et_entityset table ?

Thanks and Regards

Meenakshi
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos
The type of et_entityset is based on the type defined in the MPC class.

ls_headerdata type zcl_ze2e100_xx_mpc=>ts_salesorder.

I would always recommend to use DDIC structures but you can also create entity types manually usign SEGW.

Best Regards,

Andre

 
former_member486036
Discoverer
0 Kudos
I appreciate your effort for sharing your knowledge

 

Best Regards,

 
Former Member
0 Kudos
Very Nice Blog Andre.

Thanks for sharing.

 
bonafuwa7678
Explorer
0 Kudos
Hi Andre,

How i wish other SAP blogs were like this!

Thanks for sharing; very good stuff.
Former Member
0 Kudos
Hi, Andre

 

Fisrt, thank you for all your effort put in this detailed blog.

I've followed all the steps but I'm not able to see any of the methods in the ABAP Workbench. Can you help me with that?



 
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos
Make sure to have the check box Filter unchecked because otherwise only redefined method would be visible. So in the beginning the list would looks empty.

I updated my blog accordingly (see screen shot above)

 
Former Member
0 Kudos
hi Andree

How to get the sales order that is not in the EUR currency?

I view use the currency "EUR", but in my case in the table VBAK i have USD and MXN currency, so when i try to change the "ge" to en o es in  the URI to obtain the sales order mark a error

/sap/opu/odata/SAP/ZE2E100_<XX>_SRV/SalesOrderSet?$filter=Grossamountintransaccurrency ge 100000&$select=Salesorder,Grossamountintransaccurrency,Transactioncurrency&$format=json

 

Correct



 

When change the value in "ge" to other country mark a error



Can you help me or tell me how resolve this situation ?

Thanks

 
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos
What should be the meaning of "en" and "es"?

The Logical Operators that can be used in OData V2 are the following:

https://www.odata.org/documentation/odata-version-2-0/uri-conventions/
















































Eq Equal /Suppliers?$filter=Address/City eq 'Redmond'
Ne Not equal /Suppliers?$filter=Address/City ne 'London'
Gt Greater than /Products?$filter=Price gt 20
Ge Greater than or equal /Products?$filter=Price ge 10
Lt Less than /Products?$filter=Price lt 20
Le Less than or equal /Products?$filter=Price le 100
And Logical and /Products?$filter=Price le 200 and Price gt 3.5
Or Logical or /Products?$filter=Price le 3.5 or Price gt 200
Not Logical negation /Products?$filter=not endswith(Description,'milk')

If you want to compare different currencies you would have to perform either a calculation on the backend side to Show the amount only in one currency or you just select entries from one currency
adam_krawczyk1
Contributor
Hi Andre,

Very nice and blog showing most of things needed for manual implementation of ODATA service by SEGW transaction. That is the right starting point for those implementing ODATA when CDSs views are not yet available 🙂

I like the trick with filtering by "where (lv_osql_where_clause)" but a warning here - be careful when using join, as you can get runtime error if filter field is in two tables (then query does not know which table you refer to). If select is done on just one table / view it should work fine.

I miss only examples for sorting here, but I guess we might fix it by io_tech_request_context->get_filter( )->get_filter_string( ) applied dynamically to ORDERBY query too.

What I do not like in manual SEGW implementation is how paging is implemented. When processing big tables, showing lines between 10 000 and 10 050 for example (skip = 10 000, top = 50) needs to read 10 050 lines from database and delete 10 000 of them. But that is the only easy way to implement paging unless we are on 7.52 version or higher where OFFSET keyword is implemented for ABAP SELECT (ADBC dynamic queries may not always be allowed due to security policy).

Also worth to mention is that paging, filtering and orderby are methods available in /IWBEP/CL_MGW_DATA_UTIL ready for use. They work however on the result set, where data must be found first. When we have large results set it is much better to do sorting and paging on select query by WHERE and ORDERBY queries first to reduce retrieved results.

Finally I would mention, that implementing through CDS view is much more efficient (for example due to real paging done on database query) and should be first choice if only CDS views are available in the system.

Regards,
Adam
0 Kudos
Hi Andre,

 

I can't find SEPM_ISOE structure on my system. Can I change it on another structure?

 

Regards,

Mateusz
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos
Sure. It will work with any other structure.
abo
Active Contributor
0 Kudos
For the SALESORDERSET_GET_ENTITYSET, why should I redefine the method? I mean, what are the advantages if I have a few RFC-enabled functions and I have mapped the source. It seems that the DPC class already works as expected: correct function is invoked, boilerplate code is generated for some options.

My newbie understanding is that redefinition is required when I am not mapping anything so SAP has no idea how to fetch the data, is that correct?
grabz
Advisor
Advisor
0 Kudos

Prerequisite for the blog:

In the exercises the SEPM_ISOE CDS View will be used. This is a test view which has to be activated and filled with data.

1.Call SE11

2.View: SEPM_ISOE à  Display

3.If the View isn't active: Activate, if it's already active move to the next point

4.Call SEPM_DG

5.Choose how many records is desired to create

6.Execute

philippsathasivam
Participant
0 Kudos

Hello, great Post ! I have the Problem that when i follow the instructions, no GW_HUB appears, although service was succesfully created. Any help for that ?

philippsathasivam_0-1713883882773.png

Best regards, Philipp