It is very simple to create a webservice using only ABAP, thanks to Naresh Bammidi that showed us the way!
Basically, we start by creating a new class in SE24 implementing interface IF_HTTP_EXTENSION.
Then, we just implement the method handle_request.
The trick is to concatenate everything in a single string, using the JSON style, and set the content type by using the method set_header_field.
Check my sample code bellow:
METHOD if_http_extension~handle_request.
CONSTANTS: c_object_start TYPE c VALUE '{',
c_object_end TYPE c VALUE '}'.
DATA: lv_path_info TYPE string,
lv_request_method TYPE string,
lv_response_data TYPE string.
DATA: it_inputparams TYPE tihttpnvp,
ls_inputparams TYPE LINE OF tihttpnvp.
DATA: lv_ebeln TYPE ekpo-ebeln,
lv_ebelp TYPE ekpo-ebelp,
lv_matnr TYPE ekpo-matnr.
FIELD-SYMBOLS <fs_param> TYPE LINE OF tihttpnvp.
"Get request info
lv_path_info = server->request->get_header_field( name = '~path_info' ).
lv_request_method = server->request->get_header_field( name = '~request_method' ).
"Only GET is allowed
IF lv_request_method NE 'GET'.
CALL METHOD server->response->set_header_field( name = 'Allow' value = 'GET' ).
CALL METHOD server->response->set_status( code = '405' reason = 'Method not allowed' ).
EXIT.
ENDIF.
"Get GET parameters
CALL METHOD server->request->get_form_fields
CHANGING
fields = it_inputparams.
UNASSIGN <fs_param>.
LOOP AT it_inputparams ASSIGNING <fs_param>.
TRANSLATE <fs_param>-name TO UPPER CASE.
ENDLOOP.
CLEAR: lv_ebeln, ls_inputparams.
READ TABLE it_inputparams INTO ls_inputparams WITH KEY name = 'PO'.
lv_ebeln = ls_inputparams-value.
CLEAR ls_inputparams.
"Empty parameter
IF lv_ebeln IS INITIAL.
CALL METHOD server->response->set_status( code = '404' reason = 'Empty parameters are not allowed' ).
CALL METHOD server->response->set_cdata( data = 'There are one or more missing parameters' ).
EXIT.
ENDIF.
"Start of response data
lv_response_data = c_object_start.
"Add element: PO
lv_response_data = | { lv_response_data } "PO":" { lv_ebeln }", |.
"Add array: ITEMS
lv_response_data = | { lv_response_data } "ITEMS":[ |.
"Add items
SELECT ebelp matnr
INTO (lv_ebelp, lv_matnr)
FROM ekpo
WHERE ebeln = lv_ebeln.
lv_response_data = | { lv_response_data } { c_object_start } "NITEM":"{ lv_ebelp }","MATERIAL":"{ lv_matnr }" { c_object_end },|.
ENDSELECT.
IF sy-subrc = 0.
SHIFT lv_response_data RIGHT DELETING TRAILING space.
ENDIF.
"End of array
lv_response_data = | { lv_response_data } ] |.
"End of response data
lv_response_data = | { lv_response_data } { c_object_end } |.
"Set JSON Content-Type
CALL METHOD server->response->set_header_field( name = 'Content-Type' value = 'application/json; charset=UTF-8' ).
"Set Response Data
CALL METHOD server->response->set_cdata( data = lv_response_data ).
ENDMETHOD.
After that just publish it in SICF, into Handler list and test it.
I tested it in SoapUI 5.2.1.
Reference doc: http://scn.sap.com/docs/DOC-46463