You are on page 1of 17

Lets code CRUDQ and Function

Import operations in OData service!


Posted by Chandrashekhar Mahajan in SAP Gateway on Mar 6, 2014 7:42:38 AM
inShare

Introduction
Scenario
Procedure
Coding
1) Query Operation
2) Read Operation
3) Create Operation
4) Update Operation
5) Delete Operation
6) Function Import
Closing Remarks
Introduction
In this blog I will explain creation of simple SAP NW GW OData service which will implement Create, Read, Update,
Delete, Query and Function Import operations.
Just to make it very simple, I will just have single entity and entity set. Here I will perform these operations on Z table.
In real scenarios, you will use BAPIs. RFCs to perform these operations.
I recommend to read below documents and SAP documentation for deep understanding.
How to Develop a Gateway Service using Code based Implementation by Andre Fischer
How to Develop Query Options for an OData Service Using Code-Based Implementationby Andre
Fischer
How to Write an OData Channel Gateway Service. Part 2 - The Runtime Data Provider Class
SAP Help - SAP NetWeaver Gateway Foundation Developer Guide - SAP NetWeaver Gateway Foundation
(SAP_GWFND) - SAP Library
Code Snippet - 3.2 Data Provider Class (DPC) - SAP NetWeaver Gateway Foundation (SAP_GWFND) - SAP
Library

Scenario
We have User information table as ZUSERINFO containing below fields

Now let's create OData service which will insert, read, delete, update and query this table along with one custom
operation (UsersByCountry) as function import.
From an ABAPer perspective, This is what meant by OData operations.
OData
Operation

HTTP
Method

What it meant to an ABAPer

Create

POST

Insert <table> from <workarea>

Read

GET

Select Single * From <table> into <workarea>

Update

PUT/PATCH

Update <table> set <workarea>

Delete

DELETE

Delete from <table>

Query

GET

Select * From <table> Into Table

Function
Import

GET/POST

Everything covered by GET and POST. But only use if scenario


does not fit into CRUDQ operations.

We can correlate Entity Set as Table Type, Internal table and Entity to work area, structure!

Entity Set

Table Type or Internal Table

Entity

Structure or Work Area

Procedure
Lets go to transaction SEGW and create project as ZUSERINFO.

Now right click on Data Model and Import --> DDIC Structure option, it will display popup window. Provide DDIC
structure name. In this case table name ZUSERINFO. It will propose field and key mapping as well as object name
which will be your entity name.

We will ignore MANDT as key field and also overwrite object name. I want my field names in upper camel case
format so I will change it accordingly. Lets call entity type as User. It will look as below. Press enter.

finally our entity type User will look as below.

Now lets create Entity Set as UserCollection (or UserSet or Users). You can refer Creating High-Quality
OData Services - SAP NetWeaver Gateway Foundation (SAP_GWFND) - SAP Library
I will go with UserCollection as my entity set name.

Right click folder name Entity Sets and click create. Provide entity set name as UserCollection and Entity Type name
as User. It will display as below.

Now lets generate runtime artifacts. Click on generate runtime objects button. It will display popup as below. Keep
the default class names as-is and click on enter button.

On successful generation, you will see this kind of message log and generated artifacts. 4 classes will get generated.
2 for Data provider and 2 for Model provider.

Now register your service under service Maintenance folder. Click on Register button. Keep default values as-is
and hit enter button.

On successful registration, click Maintain button. This will open service catalog window along with option to call
Gateway Client. Click on Gateway Client button to test the service. (you can also call transaction
/IWFND/GW_CLIENT to open SAP NW Gateway client)
Append $metatda to base service URL and press execute button. If everything is fine then you will HTTP
Response as below. Metadata provides information such as Entity type, key property, properties and Entity Set name.

So far we just defined single entity type and entity set. Now its time to code CRUDQ and function import methods.

Coding

There is no specific order to implement these methods but it is always good to 1st implement query and read
operation as for Create and Update, you will need request data which you will get if you already have query/read
implemented.

1) Query Operation
First we will start implementing query operation. Before that, I will add one record in my ZUSERINFO table as

Now open Runtime artifacts folder and right click on Class ZCL_ZUSERINFO_DPC_EXT and select Go to ABAP
Workbench option. Select edit mode and redefine method USERCOLLECTION_GET_ENTITYSET.

In the simplest form, this is what minimal coding will look like in GET_ENTITYSET method.
METHODusercollection_get_entityset.

DATA:lt_userinfoTYPETABLEOFzuserinfo,
ls_userinfoLIKELINEOFlt_userinfo,
ls_entityLIKELINEOFet_entityset.

*Get data from ZUSERINFO table


SELECT*FROMzuserinfoINTOTABLElt_userinfo.

*Fill ET_ENTITYSET
LOOPATlt_userinfoINTOls_userinfo.
ls_entityuserid = ls_userinfouserid.
ls_entityfirstname = ls_userinfofirstname.
ls_entitylastname = ls_userinfolastname.
ls_entityemail
= ls_userinfoemail.
ls_entityphone
= ls_userinfophone.
ls_entitycountry= ls_userinfocountry.
APPENDls_entityTOet_entityset.
ENDLOOP.

ENDMETHOD.

We are selecting all data from table ZUSERINFO and appending the result to exporting parameter ET_ENTITYSET.
Now you can go to GW client transaction and execute
URI /sap/opu/odata/sap/ZUSERINFO_SRV/UserCollectionwhich will display one record which we already added
into Z table.

Observe the method signature. put external breakpoint in method and execute query. You will find important
information in method parameters in debugging mode.
Below table will provide brief explanation of method parameters, alternative approach to get the value of those
method parameters. Last column specifies if we need to code to implement query operation.
Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITYSET

OData Query

UserCollection?$filter=UserID eq
'123' and LastName eq 'Mahajan'

Method Parameter

Alternative way to get the value

Coding
require
d to
imple
ment
Query
Operat
ion

DATA: my_filter_options TYPE/iwbep/t_mgw_s


elect_option,
my_filter_string TYPE string.
my_filter_options =io_tech_request_contextIT_FILTER_SELECT_OP >get_filter( )->get_filter_select_options( ).
TIONS and
my_filter_string = io_tech_request_contextYes
IV_FILTER_STRING
>get_filter( )->get_filter_string( ).

OData Query

UserCollection?
$select=FirstName,LastName

Method Parameter

Alternative way to get the value

Coding
require
d to
imple
ment
Query
Operat
ion

No method parameter

data: my_select_fields type/iwbep/t_mgw_tech


_field_names.
my_select_fields =io_tech_request_contextNo
>get_select( ).

IT_ORDER

data: my_orderby_fields type/iwbep/t_mgw_tec


h_order.
my_orderby_fields =io_tech_request_contextYes
>get_orderby( ).

IV_SEARCH_STRING

data: my_search_string typestring.


my_search_string =io_tech_request_contextYes
>get_search_string( ).

UserCollection?
$orderby=FirstName,LastName
OR
UserCollection?
$orderby=FirstName
desc,LastName desc

UserCollection?search='test'

data: my_top type string.


my_top = io_tech_request_context->get_top( ).
data: my_skip type string.
my_skip = io_tech_request_context->get_skip(
Yes
).

UserCollection?$top=1

IS_PAGING-TOP

In case if we had association and


navigation between 2 entities

DATA: my_nav_path type/iwbep/t_mgw_tech_


navi.
my_nav_path =io_tech_request_contextYes
IT_NAVIGATION_PATH >get_navigation_path( ).

2) Read Operation
Now lets implement GET_ENTITY method. Go to method USERCOLLECTION_GET_ENTITY and redefine it. Below
is the minimal code that we need to have in this method.
We need to read the key values passed from query URI and then fill the export parameter ER_ENTITY.
METHODusercollection_get_entity.

DATA:ls_key_tabTYPE/iwbep/s_mgw_name_value_pair,
lv_useridTYPEzuserinfouserid,
ls_userinfoTYPEzuserinfo.

*Get the key property values


READTABLEit_key_tabWITHKEYname = 'UserID'INTOls_key_tab.

lv_userid = ls_key_tabvalue.

*Get the single record from ZUSERINFO and fill ER_ENTITY


SELECTSINGLE*FROMzuserinfoINTOls_userinfoWHEREuserid = lv_userid.

IFsysubrc = 0.
er_entityuserid = ls_userinfouserid.
er_entityfirstname = ls_userinfofirstname.
er_entitylastname = ls_userinfolastname.
er_entityemail
= ls_userinfoemail.
er_entityphone
= ls_userinfophone.
er_entitycountry = ls_userinfocountry.
ENDIF.

ENDMETHOD.
Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY

Method
Parameter

OData Query

Alternative way to get the value

Coding
require
d to
imple
ment
Query
Operat
ion

UserCollection(UserID='Test') OR
UserCollection('Test'

DATA: lt_keys TYPE/iwbep/t_mgw_tech_pairs.


lt_keys =io_tech_request_context->get_keys( ). Yes

IT_KEY_TAB

In case if we had association and


navigation between 2 entities

DATA: my_nav_path type/iwbep/t_mgw_tech_na


vi.
IT_NAVIGATION_ my_nav_path =io_tech_request_contextYes
PATH
>get_navigation_path( ).

UserCollection('Test')?
$select=FirstName,LastName

No

DATA: my_select_fields TYPE/iwbep/t_mgw_tech


_field_names.
my_select_fields =io_tech_request_contextNo
>get_select( ).

UserCollection('Test')?$format=json

No

No

No

Also note that you cannot use system query options else you will get an error as System query options
'$orderby,$skip,$top,$skiptoken,$inlinecount,' are not allowed in the requested URI
3) Create Operation
Now we will focus on create operation by redefining method USERCOLLECTION_CREATE_ENTITY. Below is the
code that will perform POST operation.
Here we are reading the request data and then filling the exporting parameter ER_ENTITY.
METHODusercollection_create_entity.
DATA:ls_request_input_dataTYPEzcl_zuserinfo_mpc=>ts_user,
ls_userinfoTYPEzuserinfo.

* Read Request Data


io_data_provider>read_entry_data(IMPORTINGes_data = ls_request_input_data).

* Fill workarea to be inserted


ls_userinfouserid= ls_request_input_datauserid.
ls_userinfofirstname = ls_request_input_datafirstname.
ls_userinfolastname= ls_request_input_datalastname.

ls_userinfoemail= ls_request_input_dataemail.
ls_userinfophone= ls_request_input_dataphone.
ls_userinfocountry= ls_request_input_datacountry.

* Insert Data in table ZUSERINFO


INSERTzuserinfoFROMls_userinfo.
IFsysubrc = 0.
er_entity = ls_request_input_data."Fill Exporting parameter ER_ENTITY
ENDIF.
ENDMETHOD.
To test POST operation, 1st execute GET operation and then press Use as Request button which will copy the
response to request window and then select operation POST and execute.
In case you execute GET operation i.e. GET_ENITITYSET and then try to perform POST operation then you will get
below kind of error. Hence make sure that you execute GET to read single entity i.e. GET_ENTITY operation and
then perform POST.

So correct steps are,


1) Execute GET to read single entity /sap/opu/odata/sap/ZUSERINFO_SRV/UserCollection('Test')
2) Click Use as Request button
3) Update your request properties.
4) Select HTTP method as POST
5) Query as /sap/opu/odata/sap/ZUSERINFO_SRV/UserCollection and execute

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY_C

OData Query

Method Parameter

Coding
required
to
implem
ent
Query
Operati
on

DATA: ls_request_input_dataTYPEzcl_zuserinfo_mpc=>ts_
/
user.
sap/opu/odata/sap/ZUSERINFO_SRV/UserColl io_data_provider->read_entry_data(IMPORTING es_data
Yes
ection
=ls_request_input_data ).

In case of Create operation, you cannot use system query options else you will get an error as
The Data Services Request contains SystemQueryOptions that are not allowed for this
Request Type
This error message comes from method PROCESS_ENTITY_SET (/IWCOR/CL_DS_PROC_DISPATCHER). Just in
case if you are curious and want to know
4) Update Operation
Now we will implement update operation by redefining method USERCOLLECTION_UPDATE_ENTITY. We need to
put below code in this method.
METHODusercollection_update_entity.
DATA:ls_request_input_dataTYPEzcl_zuserinfo_mpc=>ts_user,
ls_key_tabTYPE/iwbep/s_mgw_name_value_pair,
lv_useridTYPEzuserinfouserid,
ls_userinfoTYPEzuserinfo.

* Get key values


READTABLEit_key_tabWITHKEYname = 'UserID'INTOls_key_tab.
lv_userid = ls_key_tabvalue.
IFlv_useridISNOTINITIAL.

* Read request data


io_data_provider>read_entry_data(IMPORTINGes_data = ls_request_input_data).

* Update fields of table ZUSERINFO


UPDATEzuserinfoSETfirstname = ls_request_input_datafirstname
lastname = ls_request_input_datalastname
email
= ls_request_input_dataemail
phone = ls_request_input_dataphone
country = ls_request_input_data-country
WHEREuserid = lv_userid.
IFsysubrc = 0.
er_entity = ls_request_input_data."Fill exporting parameter ER_ENTITY
ENDIF.
ENDIF.
ENDMETHOD.
Here also first we need to execute GET operation to read the entity and then copy the response to
request using Use as Request button and execute PUT operation after editing required data. Successful
HTTP response will look as below with status code as 204.

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY_U

OData Query

Method Parameter

UserCollection('Test1
')
IT_KEY_TAB

Alternative way to get the value


DATA: lt_keys TYPE /iwbep/t_mgw_tech_pairs,
ls_key TYPE /iwbep/s_mgw_tech_pair.
lt_keys = io_tech_request_context->get_keys( ).

Coding
required
to
impleme
nt Query
Operatio
n

Yes

OData Query

Method Parameter

Alternative way to get the value

UserCollection('Test1 IO_DATA_PROVIDE io_data_provider->read_entry_data(IMPORTING es_data


')
R
=ls_request_input_data ).

Coding
required
to
impleme
nt Query
Operatio
n
Yes

5) Delete Operation
To implement Delete operation, you need to execute DELETE HTTP method for particular key. Below is the code for
method USERCOLLECTION_DELETE_ENTITY.
Here we are reading key value of the record to be deleted and executing Delete statement.
METHODusercollection_delete_entity.
DATA:ls_key_tabTYPE/iwbep/s_mgw_name_value_pair,
lv_useridTYPEzuserinfouserid.
* Read key values
READTABLEit_key_tabINTOls_key_tabWITHKEYname = 'UserID'.
lv_userid = ls_key_tabvalue.
IFlv_useridISNOTINITIAL.
* Delete record from table ZUSERINFO
DELETEFROMzuserinfoWHEREuserid = lv_userid.
ENDIF.
ENDMETHOD.
On successful record deletion, you will see HTTP response code as 204.

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY_D

OData Query

Method
Parameter

UserCollection('Test1') IT_KEY_TAB
6) Function Import

Alternative way to get the value

Coding required to
implement Query
Operation

DATA: lt_keys TYPE


/iwbep/t_mgw_tech_pairs,
ls_key TYPE
/iwbep/s_mgw_tech_pair.
lt_keys = io_tech_request_contextYes
>get_keys( ).

As per SAP documentation, Function Imports - SAP NetWeaver Gateway Foundation (SAP_GWFND) - SAP
Library
The Open Data Protocol (OData) includes standard CRUD (Create, Retrieve, Update, and Delete) operations that
map to the HTTP methods POST, GET, PUT/MERGE, and DELETE.
In addition, OData supports further service operations (function imports) that can be invoked by the HTTP methods
GET or POST for anything that cannot be mapped to the standard CRUD operations. You can implement such
additional service operations in the Service Builder by creating function imports within your data model.
For example, you could create function imports for the following custom operations:

Confirm Work Item

Check Flight Availability


While it is simple to create new function imports to invoke custom operations, if the operation you want to use can be
invoked using a standard CRUD operation, you should not create a function import. That is, you should only create
function imports for custom operations that cannot be invoked using a standard operation.
In simple terms, if an operation cannot fit into CRUD scenario then you can perform it by function import.
Suppose our ZUSERINFO table looks like below,

And we want to get users by specific country then we can implement function import. Lets call our function import as
UsersByCountry!
Right click on Data model and create function import. Provide proper name. Again refer Creating High-

Quality OData Services - SAP NetWeaver Gateway Foundation (SAP_GWFND) SAP Library

Provide required details such as mentioned below. Remember here we want to return collection of users and hence
we selected Return cardinality as 0..n with return entity set and HTTP method type as GET.

Now click on Function Import parameters and create import parameters as shown below. In this case we just want to
pass value of country and hence we will have one parameter as Country.

Finally save project, check project consistency and generate runtime objects. To check if everything is fine, in GW
client execute service metadata URL as /sap/opu/odata/sap/ZUSERINFO_SRV/$metadata which should show you
function import definition in metadata as below,

Now we will implement function import operation. Go to DPC_EXT class and redefine method
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~EXECUTE_ACTION.
Put below code to implement function import.
METHOD/iwbep/if_mgw_appl_srv_runtime~execute_action.
DATA:ls_parameterTYPE/iwbep/s_mgw_name_value_pair,
lv_countryTYPEstring,
lt_userinfoTYPETABLEOFzuserinfo,
ls_userinfoTYPEzuserinfo,
ls_entityTYPEzcl_zuserinfo_mpc=>ts_user,
lt_entitysetTYPEzcl_zuserinfo_mpc=>tt_user.

IFiv_action_name = 'UsersByCountry'." Check what action is being requested


IFit_parameterISNOTINITIAL.
* Read Function import parameter value
READTABLEit_parameterINTOls_parameterWITHKEYname = 'Country'.
IFsysubrc = 0.
lv_country = ls_parametervalue.
ENDIF.

IFlv_countryISNOTINITIAL.
SELECT*FROMzuserinfoINTOTABLElt_userinfoWHEREcountry =lv_country.
LOOPATlt_userinfoINTOls_userinfo.
ls_entityuserid= ls_userinfouserid.
ls_entityfirstname = ls_userinfofirstname.
ls_entitylastname= ls_userinfolastname.
ls_entityemail= ls_userinfoemail.
ls_entityphone= ls_userinfophone.
ls_entitycountry= ls_userinfocountry.
APPENDls_entityTOlt_entityset.
ENDLOOP.
* Call methos copy_data_to_ref and export entity set data
copy_data_to_ref(EXPORTINGis_data = lt_entityset
CHANGINGcr_data = er_data).

ENDIF.
ENDIF.
ENDIF.

ENDMETHOD.

To test function import we need to query as /sap/opu/odata/sap/ZUSERINFO_SRV/UsersByCountry?


Country='US'
If there are multiple parameters then it will be separated by comma.

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_FUNC_IMPORT

OData Query

Method
Parameter

/
sap/opu/odata/sap/ZUSERINFO_SRV/UsersByCo IT_PARAME
untry?Country='US'
TER

Alternative way to get the value

Coding
requir
ed to
imple
ment
Query
Operat
ion

DATA: my_parameter TYPE /iwbep/t_mg


w_name_value_pair.
my_parameter =io_tech_request_conte
xt->get_parameters( ).
Yes

Closing Remarks
This is very simple example of an OData service. In real case scenarios, you will have multiple entities,
relationship, association and navigation between them but when it comes to coding in DPC_EXT class

methods, you will find above explanation of each method, parameters and alternative way to get the
parameter values useful.

I hope you enjoyed reading this blog and now ready to develop your OData service! I request you to put
comments/suggestions. Please feel free if you have any different thought to improve any part of this blog
as well.
Happy Learning & Coding