Los clientes HTTP permiten la comunicacion con APIs REST externas desde ABAP. Hay dos clases principales: CL_HTTP_CLIENT (clasica) y CL_WEB_HTTP_CLIENT (moderna/Cloud).
Vision general
| Clase | Disponibilidad | Recomendacion |
|---|---|---|
CL_HTTP_CLIENT | ABAP clasico | On-Premise |
CL_WEB_HTTP_CLIENT | ABAP Cloud, desde 7.54 | Cloud, nuevos desarrollos |
CL_HTTP_CLIENT (Clasico)
1. GET-Request simple
DATA: lo_client TYPE REF TO if_http_client, lv_response TYPE string, lv_code TYPE i.
" Crear clientecl_http_client=>create_by_url( EXPORTING url = 'https://api.example.com/users' IMPORTING client = lo_client).
" Enviar requestlo_client->send( ).lo_client->receive( ).
" Leer responselv_code = lo_client->response->get_status( )-code.lv_response = lo_client->response->get_cdata( ).
" Cerrar conexionlo_client->close( ).
IF lv_code = 200. WRITE: / 'Exito:', lv_response.ELSE. WRITE: / 'Error:', lv_code.ENDIF.2. GET con parametros de Query
DATA: lo_client TYPE REF TO if_http_client, lv_url TYPE string.
" URL con parametroslv_url = 'https://api.example.com/users?status=active&limit=10'.
cl_http_client=>create_by_url( EXPORTING url = lv_url IMPORTING client = lo_client).
" O establecer parametros individualmentelo_client->request->set_form_field( name = 'status' value = 'active').
lo_client->send( ).lo_client->receive( ).
DATA(lv_response) = lo_client->response->get_cdata( ).lo_client->close( ).3. POST-Request con JSON
DATA: lo_client TYPE REF TO if_http_client, lv_json TYPE string.
" Crear cuerpo JSON
cl_http_client=>create_by_url( EXPORTING url = 'https://api.example.com/users' IMPORTING client = lo_client).
" Establecer metodo HTTPlo_client->request->set_method( if_http_request=>co_request_method_post ).
" Establecer Content-Typelo_client->request->set_header_field( name = 'Content-Type' value = 'application/json').
" Establecer cuerpolo_client->request->set_cdata( lv_json ).
" Enviarlo_client->send( ).lo_client->receive( ).
DATA(lv_status) = lo_client->response->get_status( )-code.DATA(lv_response) = lo_client->response->get_cdata( ).
lo_client->close( ).
CASE lv_status. WHEN 200 OR 201. WRITE: / 'Creado exitosamente'. WHEN 400. WRITE: / 'Solicitud invalida'. WHEN 401. WRITE: / 'No autorizado'. WHEN OTHERS. WRITE: / 'Error:', lv_status.ENDCASE.4. PUT-Request (Update)
cl_http_client=>create_by_url( EXPORTING url = 'https://api.example.com/users/123' IMPORTING client = lo_client).
lo_client->request->set_method( if_http_request=>co_request_method_put ).lo_client->request->set_header_field( name = 'Content-Type' value = 'application/json').lo_client->request->set_cdata( lv_json ).
lo_client->send( ).lo_client->receive( ).lo_client->close( ).5. DELETE-Request
cl_http_client=>create_by_url( EXPORTING url = 'https://api.example.com/users/123' IMPORTING client = lo_client).
lo_client->request->set_method( if_http_request=>co_request_method_delete ).
lo_client->send( ).lo_client->receive( ).
DATA(lv_status) = lo_client->response->get_status( )-code.lo_client->close( ).
IF lv_status = 204 OR lv_status = 200. WRITE: / 'Eliminado exitosamente'.ENDIF.6. Basic Authentication
cl_http_client=>create_by_url( EXPORTING url = 'https://api.example.com/secure' IMPORTING client = lo_client).
" Establecer Basic Authlo_client->authenticate( username = 'myuser' password = 'mypassword').
lo_client->send( ).lo_client->receive( ).lo_client->close( ).7. Bearer Token (OAuth)
DATA: lv_token TYPE string VALUE 'eyJhbGciOiJIUzI1NiIs...'.
cl_http_client=>create_by_url( EXPORTING url = 'https://api.example.com/protected' IMPORTING client = lo_client).
" Establecer header Authorizationlo_client->request->set_header_field( name = 'Authorization' value = |Bearer { lv_token }|).
lo_client->send( ).lo_client->receive( ).lo_client->close( ).8. Headers personalizados
lo_client->request->set_header_field( name = 'X-API-Key' value = 'my-api-key-12345').
lo_client->request->set_header_field( name = 'Accept' value = 'application/json').
lo_client->request->set_header_field( name = 'Accept-Language' value = 'es-ES').9. Establecer Timeout
cl_http_client=>create_by_url( EXPORTING url = 'https://api.example.com/slow' IMPORTING client = lo_client).
" Timeout en segundoslo_client->send( timeout = 30 ).lo_client->receive( timeout = 30 ).10. Certificados SSL/HTTPS
" Para certificados auto-firmadoslo_client->propertytype_accept_cookie = if_http_client=>co_enabled.
" Certificado cliente SSL (STRUST)lo_client->set_ssl_id( 'ANONYM' ). " O nombre de PSE
" Ignorar errores SSL (SOLO PARA PRUEBAS!)lo_client->propertytype_logon_popup = if_http_client=>co_disabled.CL_WEB_HTTP_CLIENT (Moderno/Cloud)
11. GET-Request (Cloud)
DATA: lo_client TYPE REF TO if_web_http_client, lo_response TYPE REF TO if_web_http_response.
TRY. " Destination desde SM59 o HTTP-URL DATA(lo_destination) = cl_http_destination_provider=>create_by_url( i_url = 'https://api.example.com/users' ).
lo_client = cl_web_http_client_manager=>create_by_http_destination( i_destination = lo_destination ).
lo_response = lo_client->execute( if_web_http_client=>get ).
DATA(lv_status) = lo_response->get_status( )-code. DATA(lv_body) = lo_response->get_text( ).
lo_client->close( ).
CATCH cx_web_http_client_error INTO DATA(lx_error). WRITE: / 'HTTP Error:', lx_error->get_text( ). CATCH cx_http_dest_provider_error INTO DATA(lx_dest). WRITE: / 'Destination Error:', lx_dest->get_text( ).ENDTRY.12. POST-Request (Cloud)
TRY. DATA(lo_destination) = cl_http_destination_provider=>create_by_url( i_url = 'https://api.example.com/users' ).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination( i_destination = lo_destination ).
DATA(lo_request) = lo_client->get_http_request( ).
" Establecer headers lo_request->set_header_field( i_name = 'Content-Type' i_value = 'application/json' ).
" Establecer cuerpo
" Ejecutar POST DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).
DATA(lv_status) = lo_response->get_status( )-code. DATA(lv_body) = lo_response->get_text( ).
lo_client->close( ).
CATCH cx_web_http_client_error cx_http_dest_provider_error INTO DATA(lx_error). WRITE: / lx_error->get_text( ).ENDTRY.13. Con Destination desde SM59
TRY. " Usar destination de SM59 DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement( comm_scenario = 'Z_MY_SCENARIO' service_id = 'Z_MY_SERVICE' ).
" O directamente por nombre DATA(lo_dest_by_name) = cl_http_destination_provider=>create_by_cloud_destination( i_name = 'MY_DESTINATION' ).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination( i_destination = lo_destination ).
" ...
CATCH cx_http_dest_provider_error INTO DATA(lx_error). WRITE: / lx_error->get_text( ).ENDTRY.Ejemplos practicos
14. Cliente REST completo
CLASS zcl_api_client DEFINITION PUBLIC. PUBLIC SECTION. TYPES: BEGIN OF ty_user, id TYPE i, name TYPE string, email TYPE string, END OF ty_user, ty_users TYPE TABLE OF ty_user WITH EMPTY KEY.
METHODS: constructor IMPORTING iv_base_url TYPE string iv_api_key TYPE string OPTIONAL.
METHODS: get_users RETURNING VALUE(rt_users) TYPE ty_users RAISING cx_web_http_client_error.
METHODS: create_user IMPORTING is_user TYPE ty_user RETURNING VALUE(rs_user) TYPE ty_user RAISING cx_web_http_client_error.
PRIVATE SECTION. DATA: mv_base_url TYPE string, mv_api_key TYPE string.
METHODS: create_client RETURNING VALUE(ro_client) TYPE REF TO if_http_client.ENDCLASS.
CLASS zcl_api_client IMPLEMENTATION. METHOD constructor. mv_base_url = iv_base_url. mv_api_key = iv_api_key. ENDMETHOD.
METHOD create_client. cl_http_client=>create_by_url( EXPORTING url = mv_base_url IMPORTING client = ro_client ).
IF mv_api_key IS NOT INITIAL. ro_client->request->set_header_field( name = 'X-API-Key' value = mv_api_key ). ENDIF.
ro_client->request->set_header_field( name = 'Accept' value = 'application/json' ). ENDMETHOD.
METHOD get_users. DATA(lo_client) = create_client( ).
lo_client->request->set_uri_path( '/users' ). lo_client->send( ). lo_client->receive( ).
DATA(lv_response) = lo_client->response->get_cdata( ). lo_client->close( ).
" Parsear JSON /ui2/cl_json=>deserialize( EXPORTING json = lv_response CHANGING data = rt_users ). ENDMETHOD.
METHOD create_user. DATA(lo_client) = create_client( ).
lo_client->request->set_uri_path( '/users' ). lo_client->request->set_method( if_http_request=>co_request_method_post ). lo_client->request->set_header_field( name = 'Content-Type' value = 'application/json' ).
DATA(lv_json) = /ui2/cl_json=>serialize( data = is_user ). lo_client->request->set_cdata( lv_json ).
lo_client->send( ). lo_client->receive( ).
DATA(lv_response) = lo_client->response->get_cdata( ). lo_client->close( ).
/ui2/cl_json=>deserialize( EXPORTING json = lv_response CHANGING data = rs_user ). ENDMETHOD.ENDCLASS.
" UsoDATA(lo_api) = NEW zcl_api_client( iv_base_url = 'https://api.example.com' iv_api_key = 'my-key').
TRY. DATA(lt_users) = lo_api->get_users( ).
DATA(ls_new_user) = lo_api->create_user( ).
CATCH cx_web_http_client_error INTO DATA(lx_error). WRITE: / lx_error->get_text( ).ENDTRY.15. Manejo de errores
TRY. cl_http_client=>create_by_url( EXPORTING url = 'https://api.example.com' IMPORTING client = lo_client ).
lo_client->send( ). lo_client->receive( ).
DATA(lv_status) = lo_client->response->get_status( ).
CASE lv_status-code. WHEN 200. " Exito DATA(lv_data) = lo_client->response->get_cdata( ).
WHEN 400. " Bad Request DATA(lv_error) = lo_client->response->get_cdata( ). WRITE: / 'Solicitud invalida:', lv_error.
WHEN 401. WRITE: / 'Autenticacion fallida'.
WHEN 403. WRITE: / 'Acceso denegado'.
WHEN 404. WRITE: / 'Recurso no encontrado'.
WHEN 500. WRITE: / 'Error del servidor'.
WHEN OTHERS. WRITE: / 'HTTP-Status:', lv_status-code, lv_status-reason. ENDCASE.
CATCH cx_root INTO DATA(lx_error). WRITE: / 'Error:', lx_error->get_text( ).
CLEANUP. IF lo_client IS BOUND. lo_client->close( ). ENDIF.ENDTRY.16. Enviar datos binarios (archivos)
DATA: lv_file_content TYPE xstring.
" Archivo como datos binarioslv_file_content = '...'. " ej. desde archivo o tabla
lo_client->request->set_method( if_http_request=>co_request_method_post ).lo_client->request->set_header_field( name = 'Content-Type' value = 'application/octet-stream').
lo_client->request->set_data( lv_file_content ).
lo_client->send( ).lo_client->receive( ).17. Multipart/Form-Data
DATA: lv_boundary TYPE string VALUE '----WebKitFormBoundary7MA4YWxk'.
lo_client->request->set_header_field( name = 'Content-Type' value = |multipart/form-data; boundary={ lv_boundary }|).
DATA(lv_body) = |--{ lv_boundary }\r\n| && |Content-Disposition: form-data; name="field1"\r\n\r\n| && |value1\r\n| && |--{ lv_boundary }\r\n| && |Content-Disposition: form-data; name="file"; filename="test.txt"\r\n| && |Content-Type: text/plain\r\n\r\n| && |File content here\r\n| && |--{ lv_boundary }--\r\n|.
lo_client->request->set_cdata( lv_body ).Notas importantes / Mejores practicas
- CL_WEB_HTTP_CLIENT para ABAP Cloud y nuevos desarrollos.
- Siempre llamar close() - tambien en caso de error (TRY-FINALLY).
- Destination (SM59) usar para endpoints configurables.
- Timeouts establecer para APIs externas lentas.
- Certificados SSL importar en STRUST para HTTPS.
- JSON serializar/deserializar con /ui2/cl_json.
- Evaluar codigos de estado HTTP para manejo de errores.
- API-Keys/Tokens no hardcodear en el codigo - usar Destinations.
- Logging implementar para debugging.
- Considerar configuracion de proxy en sistemas productivos.