[ABAP] Konstanten für gängige MIME-Typen (IF_REST_MEDIA_TYPE, CL_FXS_MIME_TYPES)

Variante 1 (IF_REST_MEDIA_TYPE)

Konstante                       MIME-Typ
--------------------------------------------------------------
gc_all                          '*/*'
gc_appl_all                     'application/*'
gc_appl_xml                     'application/xml'
gc_appl_xhtml_xml               'application/xhtml+xml'
gc_appl_atom_xml                'application/atom+xml'
gc_appl_atom_xml_feed           'application/atom+xml;type=feed'
gc_appl_atom_xml_entry          'application/atom+xml;type=entry'
gc_appl_atomcat_xml             'application/atomcat+xml'
gc_appl_atomsvc_xml             'application/atomsvc+xml'
gc_appl_opensearch_descr_xml    'application/opensearchdescription+xml'
gc_appl_all_xml                 'application/*+xml'
gc_appl_java                    'application/java'
gc_appl_java_archive            'application/java-archive'
gc_appl_json                    'application/json'
gc_appl_json_odata_verbose      'application/json;odata=verbose'
gc_appl_mac_binhex40            'application/mac-binhex40'
gc_appl_mathml_xml              'application/mathml+xml'
gc_appl_msword                  'application/msword'
gc_appl_octet_stream            'application/octet-stream'
gc_appl_onenote                 'application/onenote'
gc_appl_pdf                     'application/pdf'
gc_appl_postscript              'application/postscript'
gc_appl_rdf_xml                 'application/rdf+xml'
gc_appl_relax_ng_compact_synt   'application/relax-ng-compact-syntax'
gc_appl_rss_xml                 'application/rss+xml'
gc_appl_rtf                     'application/rtf'
gc_appl_sparql_results_json     'application/sparql-results+json'
gc_appl_sparql_results_xml      'application/sparql-results+xml'
gc_appl_trix                    'application/trix'
gc_appl_vnd_google_earthkmlxml  'application/vndgoogle-earthkml+xml'
gc_appl_vnd_google_earth_kmz    'application/vndgoogle-earthkmz'
gc_appl_vnd_mozilla_xul_xml     'application/vndmozillaxul+xml'
gc_appl_vnd_ms_cab_compressed   'application/vndms-cab-compressed'
gc_appl_vnd_ms_excel            'application/vndms-excel'
gc_appl_vnd_ms_powerpoint       'application/vndms-powerpoint'
gc_appl_vnd_ms_project          'application/vndms-project'
gc_appl_vnd_sun_wadl_xml        'application/vndsunwadl+xml'
gc_appl_voicexml_xml            'application/voicexml+xml'
gc_appl_zip                     'application/zip'
gc_audio_all                    'audio/*'
gc_audio_basic                  'audio/basic'
gc_audio_midi                   'audio/midi'
gc_audio_mpeg                   'audio/mpeg'
gc_image_all                    'image/*'
gc_image_bmp                    'image/bmp'
gc_image_gif                    'image/gif'
gc_image_jpeg                   'image/jpeg'
gc_image_png                    'image/png'
gc_image_svg_xml                'image/svg+xml'
gc_image_tiff                   'image/tiff'
gc_message_all                  'message/*'
gc_model_all                    'model/*'
gc_model_vrml                   'model/vrml'
gc_multipart_all                'multipart/*'
gc_multipart_form_data          'multipart/form-data'
gc_text_all                     'text/*'
gc_text_calendar                'text/calendar'
gc_text_css                     'text/css'
gc_text_csv                     'text/csv'
gc_text_html                    'text/html'
gc_text_javascript              'text/javascript'
gc_text_n_triples               'text/n-triples'
gc_text_n3                      'text/n3'
gc_text_plain                   'text/plain'
gc_text_tab_separated_values    'text/tab-separated-values'
gc_text_uri_list                'text/uri-list'
gc_video_all                    'video/*'
gc_video_mp4                    'video/mp4'
gc_video_mpeg                   'video/mpeg'
gc_video_quicktime              'video/quicktime'
gc_appl_www_form_url_encoded    'application/x-www-form-urlencoded'
gc_multipart_mixed              'multipart/mixed'
gc_appl_http                    'application/http'

Variante 2 (CL_FXS_MIME_TYPES)

Konstante                           MIME-Typ
--------------------------------------------------------------
CL_FXS_MIME_TYPES=>CO_BINARY        'application/octet-stream'
CL_FXS_MIME_TYPES=>CO_PDF           'application/pdf'
CL_FXS_MIME_TYPES=>CO_IMAGE_BITMAP  'image/x-ms-bmp'
CL_FXS_MIME_TYPES=>CO_IMAGE_PNG     'image/png'
CL_FXS_MIME_TYPES=>CO_IMAGE_GIF     'image/gif'
CL_FXS_MIME_TYPES=>CO_IMAGE_TIFF    'image/tiff'
CL_FXS_MIME_TYPES=>CO_IMAGE_JPEG    'image/jpeg'

[ABAP] Einfacher REST-Service (ohne OData)

Piyush Philip auf sap.com hat eine simple Möglichkeit beschrieben, wie man in ABAP einen REST-Service mit den entsprechenden CRUD-Methoden implementieren kann. Dazu ist im Wesentlichen nur eine eigene Handler-Klasse zu implementieren, die von IF_HTTP_EXTENSION erbt. Diese Handler-Klasse wird von einem Service des ICF gerufen.

  1. SE80 -> Neue Klasse anlegen
  2. In der Klasse im Reiter Interfaces: vom Interface IF_HTTP_EXTENSION erben
  3. die Interface-Methode IF_HTTP_EXTENSION~HANDLE_REQUEST implementieren (implementiert nur REST, kein OData-Sevice!)
    METHOD if_http_extension~handle_request.
    
    * Typen
        TYPES: BEGIN OF ty_json_request,
                 param1 TYPE char64,
                 param2 TYPE char64,
               END OF ty_json_request.
    
        TYPES: BEGIN OF ty_json_response,
                 success   TYPE string,
                 msg       TYPE string,
                 operation TYPE string,
               END OF ty_json_response.
    
    * Variablen
        DATA: rv_response TYPE ty_json_response.
        DATA: it_path_info TYPE stringtab.
        DATA: it_query_strings TYPE stringtab.
    
    * Header Fields auslesen
        DATA: it_header_fields TYPE tihttpnvp.
        server->request->get_header_fields( CHANGING fields = it_header_fields ).
    
    * Request Methode (POST, GET, PUT, DELETE ...)
        DATA(lv_request_method) = server->request->get_header_field( name = '~request_method' ).
    
    * URL Pathinfo
        DATA(lv_path_info) = server->request->get_header_field( name = '~path_info' ).
    * erstes '/' entfernen
        SHIFT lv_path_info LEFT BY 1 PLACES.
        SPLIT lv_path_info AT '/' INTO TABLE it_path_info.
    
    * URL Parameter (Query Strings) für Auswertung
        DATA(lv_query_string) = server->request->get_header_field( name = '~query_string' ).
        SPLIT lv_query_string AT '&' INTO TABLE it_query_strings.
    
    * Request Methoden behandeln
        CASE lv_request_method.
    * C (Create)
          WHEN 'POST'.
    * Beispiel: per Request übermittelte JSON-Daten auslesen und behandeln
    * Content-Typ auslesen
            DATA(lv_request_content_type) = server->request->get_content_type( ).
    
    * Wenn Content-Typ JSON
            IF lv_request_content_type CP if_rest_media_type=>gc_appl_json.
    * JSON-Daten auslesen und nach ABAP-Typ konvertieren -> Parameternamen müssen übereinstimmen, sonst HTTP 500!
              DATA(lv_request_cdata) = server->request->get_cdata( ).
    
              DATA: lv_request_abap TYPE ty_json_request.
    
              TRY.
                  /ui2/cl_json=>deserialize( EXPORTING json = lv_request_cdata
                                                       pretty_name = /ui2/cl_json=>pretty_mode-camel_case
                                             CHANGING  data = lv_request_abap ).
    
                CATCH cx_root INTO DATA(e_txt).
                  MESSAGE e_txt->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
              ENDTRY.
    
              rv_response = VALUE #( success   = 'true'
                                     msg       = lv_request_abap-param1 && ' | ' && lv_request_abap-param2
                                     operation = lv_request_method ).
            ELSE.
              rv_response = VALUE #( success   = 'false'
                                     msg       = 'Request content type must be application/json'
                                     operation = lv_request_method ).
            ENDIF.
    * R (Read)
          WHEN 'GET'.
            DATA(lv_param) = server->request->get_form_field( 'param' ).
    
            rv_response = VALUE #( success   = 'true'
                                   msg       = lv_param
                                   operation = lv_request_method ).
    * U (Update)
          WHEN 'PUT'.
            rv_response = VALUE #( success   = 'true'
                                   msg       = ''
                                   operation = lv_request_method ).
    * D (Delete)
          WHEN 'DELETE'.
            rv_response = VALUE #( success   = 'true'
                                   msg       = ''
                                   operation = lv_request_method ).
    
    * unerlaubte Methoden abfangen
          WHEN OTHERS.
    * Fehlercode 405 zurückgeben
            server->response->set_status( code   = cl_rest_status_code=>gc_client_error_meth_not_allwd
                                          reason = 'method not allowed' ).
    
            server->response->set_content_type( if_rest_media_type=>gc_appl_json ).
    
            server->response->set_header_field( name  = if_http_header_fields=>allow
                                                value = 'POST,GET,PUT,DELETE' ).
    
            rv_response = VALUE #( success   = 'false'
                                   msg       = 'error'
                                   operation = lv_request_method ).
        ENDCASE.
    
    * wenn erfolgreich, dann Wert zurückgeben
        IF rv_response-success = 'true'.
    * HTTP-Status 200
          server->response->set_status( code   = cl_rest_status_code=>gc_success_ok
                                        reason = 'Ok.' ).
    
    * application/json
          server->response->set_content_type( if_rest_media_type=>gc_appl_json ).
    
    * Service-Response als JSON zurückgeben
          server->response->set_cdata( data = /ui2/cl_json=>serialize( data        = rv_response
                                                                       pretty_name = /ui2/cl_json=>pretty_mode-camel_case ) ).
    
        ENDIF.
    
    ENDMETHOD.
    
  4. SICF -> neue ICF-Node (Sub-Element) unterhalb default_host -> sap -> bc als neuen unabhängigen Service anlegen
  5. in der Handlerliste des Service die erstellte Klasse als “Handler” angeben
  6. auf die neue ICF-Node rechtsklicken -> Service aktivieren
  7. auf die neue ICF-Node rechtsklicken -> Service testen
  8. URL aus Browserfenster kopieren (http://domain.de/sap/bc/servicename?sap-client=900)
  9. im Browser mir einem Rest-Plugin (FireFox-Prugin: Rested) testen

Links