Quantcast
Channel: ABAP Development
Viewing all articles
Browse latest Browse all 948

#sitHH : Exposing data to #UI5 without using SAP Gateway, Part II: back to standard

$
0
0

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 TYPESTANDARDTABLEOF ysithhsalesorder.

 

SELECT * FROM ysithhsalesorder

  INTOTABLE @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


p1.PNG


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

  CREATEPUBLIC.

 

  PUBLICSECTION.

    METHODS if_rest_application~get_root_handler REDEFINITION.

  PROTECTEDSECTION.

  PRIVATESECTION.

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

p2.PNG

p3.PNG


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

  CREATEPUBLIC.

 

  PUBLICSECTION.

    METHODS if_rest_resource~get REDEFINITION.

  PROTECTEDSECTION.

  PRIVATESECTION.

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 ISINITIAL.  " 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 TYPESTANDARDTABLEOF ysithhsalesorder.

 

    SELECT * FROM ysithhsalesorder

      INTOTABLE @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'.

        GETTIMESTAMPFIELD ls_feed-updated-datetime.

        LOOPAT salesorder ASSIGNING FIELD-SYMBOL(<f>).

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

          CONVERT DATE sy-datlo

            INTOTIMESTAMP ls_entry-updated-datetime TIMEZONE'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.


p4.PNG


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.

 

p5.PNG

 

The Result

 

p6.PNG

Yea, no differences

 

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"

 

Appendix

 

 

You can find me on Twitter and G+


Viewing all articles
Browse latest Browse all 948

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>