cancel
Showing results for 
Search instead for 
Did you mean: 

SAP Gateway - Return warning messages to service

0 Kudos

Hello,

after spending some time on google i didn't find a helping thread.. so i'll give it a try at the SCN

We've developed a gateway service to create leaverequests.

The included check returns warning messages as "leave request is in workfree time" - for example for a weekend.

The LR will still be persisted - so no exceptions.

But i want to return these messages to the gatewayservice/frontend.

I found a thread that helped me a little, but i'm not quite satisfied yet.

=>

The message will only be returned if i raise an exception.

But i don't want a 400 Bad Request.

The GW Component is updated to SP8 as suggested by Ralf Handl.

Did i do something wrong? Is it even possible to include messages in the return-body?

I tried the example code from the thread linked above.

Thanks for advice!

Greetings,

Pascal

Accepted Solutions (1)

Accepted Solutions (1)

AshwinDutt
Active Contributor
0 Kudos

Hello Pascal,

I assume that Create LeaveRequest would be a POST/Create operation through GW.

I would suggest the below way ->

Assume you already have LeaveRequest entity in GW Model.

In your GW model add another entity say ReturnError and add the fields say MessageType and MessageText.

Now create association and navigation between LeaveRequest entity and ReturnError entity with cardinality 1 to N.

In DPC_EXT class implement Create_Deep_Entity.

Here you will create deep structure which can hold Leave related data and also Error messages as well.

After processing request in backend, Use this deep structure to add messages ( message type E or S or W and corresponding messages ) and leave request data and send it back as GW response.

In the UI level check the Message Type and perform the operation accordingly in front end.

This way you can handle.

Technical help can be found here ->

Step by Step development for CREATE_DEEP_ENTITY operation

Regards,

Ashwin

0 Kudos

Hello Ashwin,

thanks for response!

This was one of my ideas but i was hoping there was a way to return the messages via the context-model/message-object.

If not, i'll suggest this to the development team

Regards,

Pascal

former_member184867
Active Contributor
0 Kudos

it is possible to return some message to the front end, without raising exception. The code is available in Success/Error/Info Message in return of Odata Service response from ECC.

Here is a working sample for you.

Code in Some Dummy DPC

------------------------------------------------------

Output in the Gateway Client

--------------------------------------------

Here you can see that I am also sending some message along with the feed. However the message appears only in the response header highlighted above. The full message is not displayed here due to restriction in the length of header values.

former_member184867
Active Contributor
0 Kudos

another option would be to pass custom header as I mentioned in the post Success/Error/Info Message in return of Odata Service response from ECC.

0 Kudos

Hi Ashwin,

i have created a new entity Errormessages and also created the association/navigation.

In the method create_deep_entity i included the errormessages into the request-structure.

But the errormessages are not in the response.

Do i have to call another method ?

I don't have to create a serviceimplementation, right?

Regards,

Pascal

AshwinDutt
Active Contributor
0 Kudos

Hello Pascal,

This is because you might have missed passing the name of navigation property in the Payload which is defined in the GW Model.

Can you please share your payload and also the navigation property name which is defined in the GW model ?

Regards,

Ashwin

0 Kudos

Hello Ashwin,

this is my PayLoad-Trace:

{

   "d" : {
     "StartDate" : "2015-02-28T00:00:00.000",
     "EndDate" : "2015-02-28T00:00:00.000",
     "RequestID" : "000C291A23A21ED49F92F9AE5A3CACD0",
     "LeaveRequestTypeCode" : "0210",
     "IllnessReason" : "B12002",
     "Approvers" : [
       {
         "ApproverID" : "00001100",
         "SeqNo" : "000"
       },
       {
         "ApproverID" : "00001246",
         "SeqNo" : "001"
       },
       {
         "ApproverID" : "00001206",
         "SeqNo" : "002"
       },
       {
         "ApproverID" : "00001200",
         "SeqNo" : "003"
       }
     ]
   }
}



The navgiation property is called Errormessages, the Relationship name ErrorMessagesOfLeaveRequest which has the association between LeaveRequest(1) and Errormessages (N).




So i also have to post the Errormessages-Element in my Request to the Gateway?


Regards,

Pascal

AshwinDutt
Active Contributor
0 Kudos

Hello Pascal,

Use the below payload and check if you are able to see all the error messages which are sent as response.

{

     "StartDate" : "2015-02-28T00:00:00.000",
     "EndDate" : "2015-02-28T00:00:00.000",
     "RequestID" : "000C291A23A21ED49F92F9AE5A3CACD0",
     "LeaveRequestTypeCode" : "0210",
     "IllnessReason" : "B12002",
     "Approvers" : [
       {
         "ApproverID" : "00001100",
         "SeqNo" : "000"
       },
       {
         "ApproverID" : "00001246",
         "SeqNo" : "001"
       },
       {
         "ApproverID" : "00001206",
         "SeqNo" : "002"
       },
       {
         "ApproverID" : "00001200",
         "SeqNo" : "003"
       }
     ],

"Errormessages":[ ]
   }

Regards,

Ashwin

0 Kudos

Unfortunately i don't receive any messages.

For tests i fill the approver-table with testdata - the gateway returns those data.

But if i send your request it doesn't return the Approvers - only the request-structure which is flat.

Any ideas?

Regards,

Pascal

AshwinDutt
Active Contributor
0 Kudos

Ok can use please share the deep structure which is defined by you inside Create_Deep_Entity method  which is used to return the error and leave request details ?

0 Kudos

Here you go:

types: begin of type_request_err.
           include type /XXX/tt_req_crea_struc.
   types: approvers type /XXX/tt_approvers,
          errormessages type bapiret2_tab,
   end of type_request_err.



It includes the request_create_structure, the Approvers-Table and Table of bapiret2 which is also defined in the gateway-entity/model.


When i delete the Errormessages-Tag in your testrequest, the approvers will be returned.

Did i miss something?

AshwinDutt
Active Contributor
0 Kudos

Structure is fine.

Ok Can you try with this please?

{

   "d" : {

     "StartDate" : "2015-02-28T00:00:00.000",
     "EndDate" : "2015-02-28T00:00:00.000",
     "RequestID" : "000C291A23A21ED49F92F9AE5A3CACD0",
     "LeaveRequestTypeCode" : "0210",
     "IllnessReason" : "B12002",
     "Approvers" : [
       {
         "ApproverID" : "00001100",
         "SeqNo" : "000"
       },
       {
         "ApproverID" : "00001246",
         "SeqNo" : "001"
       },
       {
         "ApproverID" : "00001206",
         "SeqNo" : "002"
       },
       {
         "ApproverID" : "00001200",
         "SeqNo" : "003"
       }
     ],

"Errormessages":[{ }]
   }

}



0 Kudos

Still no return

This is my testcoding. I cut out some parts which are unnecessary and absolutely random

* declaration

   types: begin of type_request_err.
           include type /XXX/tt_req_crea_struc.
   types: approvers type /XXX/tt_approver_tab,
          errormessages type bapiret2_tab,
   end of type_request_err.

* body

* CASE WHICH ENTITY_SET!
   case iv_entity_set_name.
     when 'LeaveRequestCollection'.

       lv_compare = io_expand->compare_to( 'Approvers' ).
* check if results compare
       if lv_compare eq /iwbep/if_mgw_odata_expand=>gcs_compare_result-match_equals.
         io_data_provider->read_entry_data( importing es_data = ls_request_err ).
       endif.

*     create request
       call method me->leaverequestcoll_create_entity
         exporting
           iv_entity_name          = iv_entity_name
           iv_entity_set_name      = iv_entity_set_name
           iv_source_name          = iv_source_name
           it_key_tab              = it_key_tab
           io_tech_request_context = io_tech_request_context
           it_navigation_path      = it_navigation_path
           io_data_provider        = io_data_provider
         importing
           er_entity               = ls_entity.

*     if request is valid, insert/update approvers
       if ls_entity is not initial.
         class ca_pt_req_actor definition load.
         lr_actor_agent = ca_pt_req_actor=>agent.

         loop at ls_request-approvers into ls_items.
          * insert approvers
       else.
        * rollback
       endif.

       call method mo_context->get_message_container
         receiving
           ro_message_container = lr_message_cont.

       lt_messages = lr_message_cont->get_messages( ).

       if lt_messages is not initial.
*        move-corresponding ls_entity to ls_response_err.
         loop at lt_messages into ls_messages.
           move-corresponding ls_messages to ls_bapiret2.
           append ls_bapiret2 to ls_response_err-errormessages.
         endloop.
         ls_approvers-pernr = '00001120'.
         ls_approvers-seqnr = '003'.
         append ls_approvers to ls_response_err-approvers.
         move-corresponding ls_entity to ls_response_err.

         copy_data_to_ref(
          exporting
            is_data = ls_response_err
            changing
              cr_data = er_deep_entity ).
       else.
*     create response
         if ls_entity is not initial.
           copy_data_to_ref(
           exporting
             is_data = ls_entity
           changing
             cr_data = er_deep_entity
             ).
         endif.
       endif.





This testcoding only includes the important parts.

The original coding worked for the approvers part, so i thought it should also fit for the errormessages.



Thanks!

AshwinDutt
Active Contributor
0 Kudos

Please share what is the difference between structures ' ls_response_err ' and ' ls_entity ' in the below ?

copy_data_to_ref(

          exporting

            is_data = ls_response_err

            changing

              cr_data = er_deep_entity ).


        copy_data_to_ref(

           exporting

             is_data = ls_entity

           changing

             cr_data = er_deep_entity

             ).


You can have only one structure as part of gateway response.

Ideally the response structure will be a single deep structure which will have details of request and corresponding error as well ( i assume ls_request_err is the structure which you would like to send back as response )

You need to call copy_data_to_ref method only once at the end sending ls_request_err and this deep structure would be a structure which is of type type_request_err ( Which is defined at the beginning and i assume ls_request_err is the type of type_request_err ).

Please check the above points and call copy_data_to_ref method at the last by populating ls_request_err with all the error details corresponding to each leave request.

Regards,

Ashwin

0 Kudos

As i said, this is just test coding.

ls_entity is type type_request which does not include the errormessages.

It will be called if no messages are available.

Yes, ls_request_err is the structure i want to return.

This is the last copy_data_to_ref:

copy_data_to_ref(

          exporting

            is_data = ls_response_err

            changing

              cr_data = er_deep_entity ).


So the messages are included.


Regards,

Pascal

AshwinDutt
Active Contributor
0 Kudos

Ok thanks for confirming.

In that case it should work Pascal.

What is the cardinality maintained in the GW model? can you please share ?

0 Kudos

In theory it should work, yep.. but it doesn't

It is LeaveRequest(1):ErrorMessages(N) - but it has no referential Constraints because i use the bapiret2-structure.

Should it have some? Is it obligatory?

Regards,

Pascal

former_member184867
Active Contributor
0 Kudos

Did you also evaluate the other solution proposed by me ?

0 Kudos

Hi Atanu,

yes, i did evaluate your suggestion.

But i'd rather return the messages in a deep_structure than creating new header-elements.

Because there isn't just one message to be returned.

Regards,

Pascal

former_member184867
Active Contributor
0 Kudos

Not sure, If I got it correctly. I think it can be used to return multiple messages as well.

You can write Code in DPC to create multiple messages as returned by your RFC in BAPIRETURN table

DATA: lo_container TYPE REF TO /iwbep/if_message_container.
lo_container
= me->mo_context->get_message_container( ).

lo_container
->add_message( iv_msg_type = 'S'
iv_msg_id
= 'ZZZ
iv_msg_number
= 45
iv_msg_text
= 'List of Messages'
iv_is_leading_message
= abap_false
iv_add_to_response_header
= abap_true
).


lo_container
->add_message( iv_msg_type = 'S'
iv_msg_id
= 'ZZZ’
iv_msg_number
= 45
iv_msg_text
= 'Test Msg 2'
iv_is_leading_message
= abap_false
iv_add_to_response_header
= abap_true
).


lo_container
->add_message( iv_msg_type = 'S'
iv_msg_id
= 'ZZZ’
iv_msg_number
= 45
iv_msg_text
= 'Test Msg 3'
iv_is_leading_message
= abap_false
iv_add_to_response_header
= abap_true
).

The message in ZZZ/45 is '&1 &2 &3 &4'  i.e just a place holder.

If you run the service you will get the response headers with all the messages. you need to test it in REST client as the GATEWAY CLIENT would truncate the result  for header length limitations. In my case the sap-message response header looks like '

<notification xmlns:sap="http://www.sap.com/Protocols/SAPData"><code>/ZZZ/045</code><message>List of Messages</message><severity>info</severity><target></target><details><detail><code>/ZZZ/045</code><message>Test Msg 2</message><target></target><severity>info</severity></detail><detail><code>/IWBEP/ZZZ/045</code><message>Test Msg 3</message><target></target><severity>info</severity></detail></details></notification>'. If I format the value in some XML parser I get the nice response like


<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns:sap="http://www.sap.com/Protocols/SAPData">
  
<code>/ZZZ/045</code>
  
<message>List of Messages</message>
  
<severity>info</severity>
  
<target />
  
<details>
  
<detail>
  
<code>/ZZZ/045</code>
  
<message>Test Msg 2</message>
  
<target />
  
<severity>info</severity>
  
</detail>
  
<detail>
  
<code>/ZZZ/045</code>
  
<message>Test Msg 3</message>
  
<target />
  
<severity>info</severity>
  
</detail>
  
</details>
</notification>

former_member184867
Active Contributor
0 Kudos

also you can get the same message response in JSON format by specifying $format=json in the URL.

{"code":"/IZZZ/045","message":"List of Messages","severity":"info","target":"","details":[{"code":"/ZZZ/045","message":"Test Msg 2","target":"","severity":"info"},

{"code":"/ZZZ/045","message":"Test Msg 3","target":"","severity":"info"}]

}

0 Kudos

Hi Atanu,

i tried the following coding:

        lr_message_cont->add_message(
         exporting
           iv_msg_type = 'S'
           iv_msg_id = 'ZZZ'
           iv_msg_number = '45'
           iv_msg_text = 'List of Messages'
           iv_is_leading_message = abap_false
           iv_add_to_response_header = abap_true
).


But i don't get the message in the response.



With URL/LeaveRequestCollection?$format=json i get the following error:


"The Data Services Request contains SystemQueryOptions that are not allowed for this Request Type"



Any ideas?

Is there a customizing for such things as headers? or deep structure ?

Thanks!

former_member184867
Active Contributor
0 Kudos

remove the '$format=json' from the URL. Also I hope you have message class ZZZ with message number 45 in your system.

0 Kudos

It's not the ZZZ message class, i just inserted your values because i don't want to show the coding of our products/customer

But still no message in response

former_member184867
Active Contributor
0 Kudos

Can you share the screenshot of the rest client/browser of your test ?

0 Kudos

This is the Request:

{

   "d" : {

     "StartDate" : "2015-02-28T00:00:00.000",

     "EndDate" : "2015-02-28T00:00:00.000",

     "RequestID" : "000C291A23A21ED49F92F9AE5A3CACD0",

     "LeaveRequestTypeCode" : "0210",

     "IllnessReason" : "B12002",

     "Approvers" : [

       {

         "ApproverID" : "00001100",

         "SeqNo" : "000"

       },

       {

         "ApproverID" : "00001246",

         "SeqNo" : "001"

       },

       {

         "ApproverID" : "00001206",

         "SeqNo" : "002"

       },

       {

         "ApproverID" : "00001200",

         "SeqNo" : "003"

       }

     ],

"Errormessages":[{ }]

   }

}

This is the header:

content-type: application/atom+xml;type=entry; charset=utf-8

content-encoding: gzip

content-length: 860

dataserviceversion: 2.0

server: SAP NetWeaver Application Server / ABAP 731

This is the response:

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xml:base="URL">

<id>
URL/LeaveRequestCollection(RequestID='000C291A23A21ED4B09B09FE4E388CD0',VersionNumber=0)

</id>

<title type="text">

LeaveRequestCollection(RequestID='000C291A23A21ED4B09B09FE4E388CD0',VersionNumber=0)

</title>

<updated>

2015-03-02T12:33:28Z

</updated>

<category term="HCM_LEAVEMANAGEMENT_SRV.LeaveRequest" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />

<link href="LeaveRequestCollection(RequestID='000C291A23A21ED4B09B09FE4E388CD0',VersionNumber=0)" rel="self" title="LeaveRequest" />

<link href="LeaveRequestCollection(RequestID='000C291A23A21ED4B09B09FE4E388CD0',VersionNumber=0)/Approvers" rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Approvers" type="application/atom+xml;type=feed" title="Approvers">

<m:inline />

</link>

<link href="LeaveRequestCollection(RequestID='000C291A23A21ED4B09B09FE4E388CD0',VersionNumber=0)/Errormessages" rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Errormessages" type="application/atom+xml;type=feed" title="Errormessages">

<m:inline />

</link>

<link href="LeaveRequestCollection(RequestID='000C291A23A21ED4B09B09FE4E388CD0',VersionNumber=0)/$links/Approvers" rel="http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks/Approvers" type="application/xml" title="Approvers" />

<link href="LeaveRequestCollection(RequestID='000C291A23A21ED4B09B09FE4E388CD0',VersionNumber=0)/$links/Errormessages" rel="http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks/Errormessages" type="application/xml" title="Errormessages" />

<content type="application/xml">

<m:properties>
<d:RequestID>
000C291A23A21ED4B09B09FE4E388CD0

</d:RequestID>

<d:VersionNumber>

0

</d:VersionNumber>

<d:Status />

<d:StatusDescr />

<d:LeaveRequestTypeCode>

0210

</d:LeaveRequestTypeCode>

<d:LeaveRequestTypeDescription />

<d:StartDate>

2015-02-28T00:00:00

</d:StartDate>

<d:StartTime>

PT00H00M00S

</d:StartTime>

<d:EndDate>

2015-02-28T00:00:00

</d:EndDate>

<d:EndTime>

PT00H00M00S

</d:EndTime>

<d:Duration />

<d:FullWorkingDayIndicator>

true

</d:FullWorkingDayIndicator>

<d:SubmDate m:null="true" />

<d:RequesterID>

00001120

</d:RequesterID>

<d:RequesterUser />

<d:RequesterName />

<d:ApproverID>

00001100

</d:ApproverID>

<d:ApproverUser />

<d:ApproverName />

<d:AdditionalInformation01 />

<d:AdditionalInformation02 />

<d:AdditionalInformation03 />

<d:AdditionalInformation04 />

<d:AdditionalInformation05 />

<d:AdditionalInformation06 />

<d:AdditionalInformation07 />

<d:AdditionalInformation08 />

<d:AdditionalInformation09 />

<d:AdditionalInformation10 />

<d:IsUpdatable>

false

</d:IsUpdatable>

<d:IsDeletable>

false

</d:IsDeletable>

<d:CurrentNotice />

<d:PastNotice />

<d:IsDataReadOnly>

false

</d:IsDataReadOnly>

<d:IsNoticeReadOnly>

false

</d:IsNoticeReadOnly>

<d:IllnessReason>

B12002

</d:IllnessReason>

<d:IllnessReasonDescr />

</m:properties>
</content>

</entry>

AshwinDutt
Active Contributor
0 Kudos

Hello Pascal,

Please find the below details which is working for me :

GW Model ->

Code ->

Response ->

Just a sample code detail for test purpose.

You can fill dynamically and send back response.

Regards,

Ashwin

former_member184867
Active Contributor
0 Kudos

At this stage it is little strange to me.

This is how it works for me...

Code in CREATE_ENTITY in DPC:

In Chrome REST Client

Request :

Response:

0 Kudos

Hi Ashwin,

i took your coding as a template, designed mine like yours .. still not working

I'll create a test-project and do it like you did .. to find out if its the gateway itself that's not working the way it should...

To be sure: The GW_CORE component should at least be Relase 200 SP 0008, right?

Also it is a 7.31 SP11 EHP6 System.

By the way:

In Transaction /IWFND/GW_CLIENT i get the following message : HTTP Receive failed: ICM_HTTP_CONNECTION_FAILED

I did the same as you did, just with the other URI, Token and Body.

Are there any limitations for the length of the response?

I don't get why this isn't working.

When there's only the Approvers-Table in the PayLoad, i get a 201 and my testdata are returned.


If i include the errormessage in the PayLoad, i don't even receive the Approvers anymore .. debugging didn't get me any further

Any ideas left?

AshwinDutt
Active Contributor
0 Kudos

Hello Pascal,

I don't think there is something like this will work only with the higher releases.

This has worked for lower releases as well for me.

It should work in yours as well as this kind of scenarios are always encountered.

However the below are my SP levels for the reference:

GW 7.31 ->

GW_CORE : Release 200 SP 06

IW_FND : Release 250 SP 06

ECC 6.0 ->

IW_BEP : Release 200 SP 08

I would suggest to create a new project and just model the GW service exactly the same way i have done. Check if this is working.

Once it works then now create a new project and create entities newly as per your use case and check again.

Regarding error In Transaction /IWFND/GW_CLIENT with message : HTTP Receive failed: ICM_HTTP_CONNECTION_FAILED, your basis folks can help you in resolving this.

Regards,

Ashwin

0 Kudos

Hi Ashwin,

i couldn't solve the problem by your solution.

It doesn't return anything.

Could you please share the Structures and the EDM-Coretypes?

Thanks!


Regards,

Pascal

AshwinDutt
Active Contributor
0 Kudos

Hello Pascal,

In which format you are getting the response ? XML ?

Can you just try to get the response in JSON and check if you are able to see desired response ?

Just add one more header ' Accept ' with value as ' application/json '  and fire the service.

However details of Entities with Edm Types are below ->

1. PostData

Property Name - RequestID

Edm Type - Edm.String

2. AppData

Property Name - AppID , Edm Type - Edm.String

Property Name - SeqID , Edm Type - Edm.String

3. ErrorRet

Property Name - MessTyp,  Edm Type - Edm.String

Property Name - MessText, Edm Type - Edm.String

Structures which are created by GW Service Builder in Model Class :

types:

   begin of TS_POSTDATA,

      REQUESTID type C length 30,

   end of TS_POSTDATA. .

   types:

TT_POSTDATA type standard table of TS_POSTDATA. .


   types:

   begin of TS_APPDATA,

      APPID type C length 5,

      SEQID type C length 2,

   end of TS_APPDATA. .

   types:

TT_APPDATA type standard table of TS_APPDATA. .


   types:

   begin of TS_ERRORRET,

      MESSTYP type C length 1,

      MESSTEXT type C length 50,

   end of TS_ERRORRET. .

   types:

TT_ERRORRET type standard table of TS_ERRORRET. .


If this is not working then we can try with other options.


Regards,

Ashwin

Answers (0)