Application Development 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: 
UweFetzer_se38
Active Contributor

You may (should) have read part I of this blog post already to understand the motivation why I haven't used SAP Gateway for this short example.

In part I you'll also find some information / coding I'm not going to repeat here.

The Motivation

The other day one of my customers upgraded his system (finally) to the most recent enhancement pack and I thought to myself "What A Wonderful World" no no no, "could I write my example just with the standard tools now?". I've played around with my own NW 7.40 system and with just a little adjustment of the UI5 application it worked.

Just today renald.wittwer commented on part I of the blog post that he used my example in one of his projects. Nice 🙂 But also this was the reason for this part II. If you are already on a current Netweaver release (I think with NW 7.31 this already should work), you can (or better should) use the SAP standard.

The Solution

Instead of using ADL by dj.adams we use the really nice REST framework around the classes cl_rest_http_handler and cl_rest_resource.

Instead of using my JSON document class we use the standard CALL TRANSFORMATION

The Data

No changes to the original example.

The JSON document



DATA salesorders TYPE STANDARD TABLE OF ysithhsalesorder.



SELECT * FROM ysithhsalesorder


  INTO TABLE @salesorders.



DATA(lo_json_writer) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).


CALL TRANSFORMATION id SOURCE itab = salesorders RESULT XML lo_json_writer.


cl_demo_output=>display_json( lo_json_writer->get_output( ) ).







Result



As you can see, the only difference is that the JSON fieldnames (labels) are all in Upper Case now.

The Call

The standard REST framework is quite similar build like DJ Adams ADL (dispatcher/handler -> resource) and self explaining.

The Handler



CLASS ysithh_rest_test DEFINITION


  PUBLIC


  FINAL


  INHERITING FROM cl_rest_http_handler


  CREATE PUBLIC .



  PUBLIC SECTION.


    METHODS if_rest_application~get_root_handler REDEFINITION.


  PROTECTED SECTION.


  PRIVATE SECTION.


ENDCLASS.



CLASS ysithh_rest_test IMPLEMENTATION.



  METHOD if_rest_application~get_root_handler.



    DATA(lo_router) = NEW cl_rest_router( ).


    lo_router->attach( iv_template = '/orders' iv_handler_class = 'YSITHH_REST_SALESORDERS_TEST' ).



    ro_root_handler = lo_router.


  ENDMETHOD.



ENDCLASS.







And again: don't forget to enter the dispatcher class into the ICF path via transaction SICF


The Resource

Not needed but interesting: In my resource, this time I'm also handling the so called "content negotiation", means that I'm asking what type of content the client wants to get as response.


CLASS ysithh_rest_salesorders_test DEFINITION


  PUBLIC


  INHERITING FROM cl_rest_resource


  FINAL


  CREATE PUBLIC .



  PUBLIC SECTION.


    METHODS if_rest_resource~get REDEFINITION.


  PROTECTED SECTION.


  PRIVATE SECTION.


ENDCLASS.



CLASS ysithh_rest_salesorders_test IMPLEMENTATION.



  METHOD if_rest_resource~get.



    DATA(lo_entity) = mo_response->create_entity( ).



    DATA:


      lt_supp_cont_type TYPE string_table,


      lv_content_type   TYPE string,


      lv_accept         TYPE string.



* create the list or the content types supported by this REST server


    lt_supp_cont_type = VALUE #(


      ( if_rest_media_type=>gc_appl_json )


      ( if_rest_media_type=>gc_appl_xml )


      ( if_rest_media_type=>gc_text_plain )


      ( if_rest_media_type=>gc_appl_atom_xml_feed )


    ).



* get accept value from REST client


    lv_accept = mo_request->get_header_field( if_http_header_fields=>accept ).



* find the best "matching" content type from the supported list using the client's input


    TRY.


        lv_content_type = cl_rest_http_utils=>negotiate_content_type(


          iv_header_accept         = lv_accept


          it_supported_content_type = lt_supp_cont_type ).


        IF lv_content_type IS INITIAL.  " no supported format found -> http 406


          mo_response->set_status( cl_rest_status_code=>gc_client_error_not_acceptable ).


          mo_response->set_reason( if_http_status=>reason_406 ).


          RETURN.


        ENDIF.


      CATCH cx_rest_parser_error.


        mo_response->set_status( cl_rest_status_code=>gc_server_error_internal ).


        mo_response->set_reason( if_http_status=>reason_500 ).


        RETURN.


    ENDTRY.



    mo_response->set_header_field(


      EXPORTING


        iv_name = 'Content-Type'    " Header Name


        iv_value = lv_content_type    " Header Value


    ).



    DATA salesorder TYPE STANDARD TABLE OF ysithhsalesorder.



    SELECT * FROM ysithhsalesorder


      INTO TABLE @salesorder.



    CASE lv_content_type.


      WHEN if_rest_media_type=>gc_appl_json.


        " Transform data to JSON


        DATA(lo_json_writer) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).


        CALL TRANSFORMATION id SOURCE itab = salesorder RESULT XML lo_json_writer.


        lo_entity->set_content_type( if_rest_media_type=>gc_appl_json ).


        lo_entity->set_binary_data( lo_json_writer->get_output( ) ).



      WHEN if_rest_media_type=>gc_appl_xml.


        " Transform data to XML


        CALL TRANSFORMATION id SOURCE itab = salesorder RESULT XML DATA(lv_xml).


        lo_entity->set_content_type( if_rest_media_type=>gc_appl_xml ).


        lo_entity->set_binary_data( lv_xml ).



      WHEN if_rest_media_type=>gc_appl_atom_xml_feed.


        " Transform data to Atom


        DATA: ls_feed  TYPE if_atom_types=>feed_s,


              ls_entry TYPE if_atom_types=>entry_s.


        ls_feed-id-uri = 'http://www.sap.com'.


        GET TIME STAMP FIELD ls_feed-updated-datetime.


        LOOP AT salesorder ASSIGNING FIELD-SYMBOL(<f>).


          ls_entry-title-text = | { <f>-id }-{ <f>-company_short }|.


          CONVERT DATE sy-datlo


            INTO TIME STAMP ls_entry-updated-datetime TIME ZONE 'UTC'.


          ls_entry-title-type = if_atom_types=>gc_content_text.


          APPEND ls_entry TO ls_feed-entries.


        ENDLOOP.


        DATA(lo_provider) = NEW cl_atom_feed_prov( ).


        lo_provider->set_feed( ls_feed ).


        lo_provider->write_to( lo_entity ).



      WHEN if_rest_media_type=>gc_text_plain.


        lo_entity->set_string_data( 'Content type:' && lv_content_type ).


    ENDCASE.



    mo_response->set_status( cl_rest_status_code=>gc_success_ok ).


    mo_response->set_header_field(


      EXPORTING


        iv_name = 'Access-Control-Allow-Origin'    " Name of the header field


        iv_value = '*'    " HTTP header field value


    ).



  ENDMETHOD.



ENDCLASS.






The Test

In this case we have to use a REST client like the Chrome plug-in "Postman", because we have to send the "Accept" header field for the "content negotiation".

No surprises here, result is like in part I except of the upper case labels.



The App

The UI5 application is the same like in part I. The only adjustments you have to make is the new URL in the controller.js and the labels in main.view.xml. The labels must be all in upper case now.

The Result

Yea, no differences :lol:

Epilogue

The JSON document class is not dead yet. If you need special handlings of the JSON input/output like date format, lower case, table appends etc. (more features you can find in the wiki on Github) you still can and should use the class. Also the class is still in "standard maintenance" :wink:

Appendix

You can find me on Twitter and G+

2 Comments