Skip to Content

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


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

  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

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

  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.


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+

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

Leave a Reply