RAP External API Consumption - Consommer des services REST dans ABAP Cloud

Catégorie
RAP
Publié
Auteur
Johannes

Les APIs REST externes sont un element central des applications cloud modernes. Dans ABAP Cloud et RAP, il existe des methodes standardisees pour connecter des services externes de maniere securisee et robuste. Cet article presente le workflow complet de la configuration a l’implementation.

Apercu : Integration d’API dans RAP

AspectDescription
HTTP ClientCL_WEB_HTTP_CLIENT_MANAGER pour les appels cloud-native
ConfigurationCommunication Arrangements pour des credentials securises
JSON/UI2/CL_JSON ou XCO pour la serialisation
Integration RAPCustom Entities ou Determinations/Actions
Gestion des erreursLogique de retry, timeouts, gestion des exceptions

Prerequis

Avant de pouvoir consommer des APIs externes dans ABAP Cloud, vous avez besoin de :

  1. Communication Scenario - Definit le type de communication
  2. Communication System - Decrit le systeme cible
  3. Communication Arrangement - Relie le Scenario au System
┌────────────────────────────────────────────────────────────┐
│ Systeme ABAP Cloud │
│ │
│ ┌──────────────────┐ ┌─────────────────────────────┐ │
│ │ Communication │ │ Communication Arrangement │ │
│ │ Scenario │───>│ │ │
│ │ Z_WEATHER_API │ │ Scenario: Z_WEATHER_API │ │
│ └──────────────────┘ │ System: WEATHER_SERVICE │ │
│ │ Service: /weather │ │
│ ┌──────────────────┐ │ │ │
│ │ Communication │───>│ Auth: OAuth2 / API-Key │ │
│ │ System │ └─────────────────────────────┘ │
│ │ WEATHER_SERVICE │ │ │
│ │ api.weather.com │ │ │
│ └──────────────────┘ ▼ │
│ ┌─────────────────────────────┐ │
│ │ HTTP Destination │ │
│ │ cl_http_destination_provider│ │
│ └─────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘

Creer un Communication Scenario

1. Definition du service sortant

" Outbound Service: Z_WEATHER_OUTBOUND
" Service ID: Z_WEATHER_OS_REST
" Service Type: HTTP
@EndUserText.label: 'Weather API Outbound Service"
define outbound service Z_WEATHER_OS_REST {
service binding Z_WEATHER_SB;
}

2. Communication Scenario

Le Communication Scenario est cree dans ADT sous Other ABAP Repository ObjectsCommunication ManagementCommunication Scenario :

<?xml version="1.0" encoding="utf-8"?>
<scn:scenario xmlns:scn="http://sap.com/xi/BASIS/Communication"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
scn:id="Z_WEATHER_API"
scn:version="1">
<scn:label>Weather API Integration</scn:label>
<scn:description>Scenario pour connexion Weather API</scn:description>
<scn:allowedInstances>MULTIPLE</scn:allowedInstances>
<scn:communicationType>OUTBOUND</scn:communicationType>
<scn:outboundServices>
<scn:service scn:id="Z_WEATHER_OS_REST" scn:authMethod="BASIC_OR_OAUTH"/>
</scn:outboundServices>
</scn:scenario>

3. Configurer le Communication Arrangement

Dans le Fiori Launchpad sous Communication Arrangements :

ChampValeur
ScenarioZ_WEATHER_API
Arrangement NameZ_WEATHER_PROD
Communication SystemWEATHER_API_SYSTEM
Service Path/api/v1
AuthenticationOAuth 2.0 Client Credentials

HTTP Client dans ABAP Cloud

Appel API de base

CLASS zcl_weather_api DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_weather_response,
location TYPE string,
temperature TYPE decfloat16,
humidity TYPE i,
condition TYPE string,
wind_speed TYPE decfloat16,
updated_at TYPE timestamp,
END OF ty_weather_response.
METHODS get_current_weather
IMPORTING iv_city TYPE string
RETURNING VALUE(rs_result) TYPE ty_weather_response
RAISING cx_http_dest_provider_error
cx_web_http_client_error.
PRIVATE SECTION.
CONSTANTS:
c_comm_scenario TYPE if_com_scenario_factory=>ty_cscn_id
VALUE 'Z_WEATHER_API',
c_outbound_service TYPE if_com_outbound_api_factory=>ty_service_id
VALUE 'Z_WEATHER_OS_REST'.
ENDCLASS.
CLASS zcl_weather_api IMPLEMENTATION.
METHOD get_current_weather.
DATA lo_client TYPE REF TO if_web_http_client.
TRY.
" 1. Recuperer le Communication Arrangement
DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = c_comm_scenario
service_id = c_outbound_service
).
" 2. Creer le HTTP Client
lo_client = cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
" 3. Configurer la requete
DATA(lo_request) = lo_client->get_http_request( ).
lo_request->set_uri_path( |/weather?city={ cl_web_http_utility=>escape_url( iv_city ) }| ).
lo_request->set_header_field(
i_name = 'Accept"
i_value = 'application/json"
).
" 4. Executer la requete
DATA(lo_response) = lo_client->execute( if_web_http_client=>get ).
DATA(lv_status) = lo_response->get_status( )-code.
" 5. Traiter la reponse
IF lv_status = 200.
DATA(lv_json) = lo_response->get_text( ).
/ui2/cl_json=>deserialize(
EXPORTING
json = lv_json
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
CHANGING
data = rs_result
).
ELSE.
" Gestion des erreurs
DATA(lv_error_body) = lo_response->get_text( ).
RAISE EXCEPTION TYPE cx_web_http_client_error.
ENDIF.
CATCH cx_http_dest_provider_error cx_web_http_client_error.
RAISE.
CLEANUP.
IF lo_client IS BOUND.
lo_client->close( ).
ENDIF.
ENDTRY.
ENDMETHOD.
ENDCLASS.

Parsing et mapping JSON

Structures JSON complexes

" Structure de reponse API
TYPES:
BEGIN OF ty_coord,
lat TYPE decfloat16,
lon TYPE decfloat16,
END OF ty_coord,
BEGIN OF ty_weather_detail,
id TYPE i,
main TYPE string,
description TYPE string,
icon TYPE string,
END OF ty_weather_detail,
tt_weather_details TYPE STANDARD TABLE OF ty_weather_detail WITH EMPTY KEY,
BEGIN OF ty_main,
temp TYPE decfloat16,
feels_like TYPE decfloat16,
temp_min TYPE decfloat16,
temp_max TYPE decfloat16,
pressure TYPE i,
humidity TYPE i,
END OF ty_main,
BEGIN OF ty_full_response,
coord TYPE ty_coord,
weather TYPE tt_weather_details,
main TYPE ty_main,
name TYPE string,
cod TYPE i,
END OF ty_full_response.
METHOD parse_weather_response.
DATA ls_response TYPE ty_full_response.
" Parser le JSON avec structures imbriquees
/ui2/cl_json=>deserialize(
EXPORTING
json = iv_json
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
CHANGING
data = ls_response
).
" Mapper vers la structure cible
rs_weather = VALUE #(
location = ls_response-name
temperature = ls_response-main-temp
humidity = ls_response-main-humidity
condition = VALUE #( ls_response-weather[ 1 ]-description OPTIONAL )
latitude = ls_response-coord-lat
longitude = ls_response-coord-lon
).
ENDMETHOD.

Mapping de noms pour conventions differentes

" L'API utilise snake_case, ABAP utilise camelCase
TYPES:
BEGIN OF ty_api_response,
user_id TYPE string, " API: user_id
first_name TYPE string, " API: first_name
last_name TYPE string, " API: last_name
email_addr TYPE string, " API: email_addr
created_at TYPE string, " API: created_at
END OF ty_api_response.
METHOD deserialize_with_mapping.
" pretty_mode-extended pour le mapping snake_case vers ABAP
/ui2/cl_json=>deserialize(
EXPORTING
json = iv_json
pretty_name = /ui2/cl_json=>pretty_mode-extended
CHANGING
data = rs_result
).
ENDMETHOD.

Requete POST avec body JSON

Envoyer des donnees vers une API externe

CLASS zcl_order_api DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_order_item,
product_id TYPE string,
quantity TYPE i,
price TYPE decfloat16,
END OF ty_order_item,
tt_order_items TYPE STANDARD TABLE OF ty_order_item WITH EMPTY KEY,
BEGIN OF ty_order_request,
customer_id TYPE string,
order_date TYPE string,
shipping_addr TYPE string,
items TYPE tt_order_items,
END OF ty_order_request,
BEGIN OF ty_order_response,
order_id TYPE string,
status TYPE string,
total_amount TYPE decfloat16,
estimated_date TYPE string,
END OF ty_order_response.
METHODS create_order
IMPORTING is_order TYPE ty_order_request
RETURNING VALUE(rs_result) TYPE ty_order_response
RAISING cx_http_dest_provider_error
cx_web_http_client_error.
ENDCLASS.
CLASS zcl_order_api IMPLEMENTATION.
METHOD create_order.
DATA lo_client TYPE REF TO if_web_http_client.
TRY.
" Recuperer la destination
DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_ORDER_API"
service_id = 'Z_ORDER_OS_REST"
).
" Creer le HTTP Client
lo_client = cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
" Body de la requete en JSON
DATA(lv_json_body) = /ui2/cl_json=>serialize(
data = is_order
compress = abap_true
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
).
" Configurer la requete
DATA(lo_request) = lo_client->get_http_request( ).
lo_request->set_uri_path( '/orders' ).
lo_request->set_header_field(
i_name = 'Content-Type"
i_value = 'application/json"
).
lo_request->set_header_field(
i_name = 'Accept"
i_value = 'application/json"
).
lo_request->set_text( lv_json_body ).
" Executer le POST
DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).
DATA(lv_status) = lo_response->get_status( )-code.
" Traiter la reponse
IF lv_status = 201 OR lv_status = 200.
/ui2/cl_json=>deserialize(
EXPORTING
json = lo_response->get_text( )
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
CHANGING
data = rs_result
).
ELSE.
RAISE EXCEPTION TYPE cx_web_http_client_error.
ENDIF.
CLEANUP.
IF lo_client IS BOUND.
lo_client->close( ).
ENDIF.
ENDTRY.
ENDMETHOD.
ENDCLASS.

Authentification

Authentification par cle API

METHOD call_with_api_key.
DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_API_SCENARIO"
service_id = 'Z_API_SERVICE"
).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
DATA(lo_request) = lo_client->get_http_request( ).
" Cle API dans le header
lo_request->set_header_field(
i_name = 'X-API-Key"
i_value = lv_api_key " Depuis le Secure Store ou la Destination
).
" Ou comme parametre de requete
lo_request->set_uri_path( |/data?api_key={ lv_api_key }| ).
DATA(lo_response) = lo_client->execute( if_web_http_client=>get ).
lo_client->close( ).
ENDMETHOD.

OAuth 2.0 Client Credentials

OAuth est gere automatiquement via le Communication Arrangement :

Configuration du Communication System :
┌────────────────────────────────────────┐
│ Parametres OAuth 2.0 │
├────────────────────────────────────────┤
│ Token Endpoint: /oauth/token │
│ Client ID: my-client-id │
│ Client Secret: ******** │
│ Scope: api.read api.write │
└────────────────────────────────────────┘
" Avec OAuth, le token est automatiquement obtenu et renouvele
METHOD call_with_oauth.
" Le Communication Arrangement contient la configuration OAuth
DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_OAUTH_API"
service_id = 'Z_OAUTH_SERVICE"
).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
" Le header Authorization est ajoute automatiquement
DATA(lo_response) = lo_client->execute( if_web_http_client=>get ).
lo_client->close( ).
ENDMETHOD.

Definir manuellement un Bearer Token

METHOD call_with_bearer_token.
DATA(lo_request) = lo_client->get_http_request( ).
" Bearer Token depuis un appel d'authentification precedent
lo_request->set_header_field(
i_name = 'Authorization"
i_value = |Bearer { lv_access_token }|
).
DATA(lo_response) = lo_client->execute( if_web_http_client=>get ).
ENDMETHOD.

Gestion des erreurs et logique de retry

Classe d’exception robuste

CLASS zcx_external_api_error DEFINITION
PUBLIC
INHERITING FROM cx_static_check
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_t100_message.
INTERFACES if_t100_dyn_msg.
CONSTANTS:
BEGIN OF connection_failed,
msgid TYPE symsgid VALUE 'Z_API',
msgno TYPE symsgno VALUE '001',
attr1 TYPE scx_attrname VALUE 'MV_URL',
attr2 TYPE scx_attrname VALUE '',
attr3 TYPE scx_attrname VALUE '',
attr4 TYPE scx_attrname VALUE '',
END OF connection_failed,
BEGIN OF http_error,
msgid TYPE symsgid VALUE 'Z_API',
msgno TYPE symsgno VALUE '002',
attr1 TYPE scx_attrname VALUE 'MV_STATUS_CODE',
attr2 TYPE scx_attrname VALUE 'MV_STATUS_TEXT',
attr3 TYPE scx_attrname VALUE '',
attr4 TYPE scx_attrname VALUE '',
END OF http_error,
BEGIN OF timeout,
msgid TYPE symsgid VALUE 'Z_API',
msgno TYPE symsgno VALUE '003',
attr1 TYPE scx_attrname VALUE 'MV_URL',
attr2 TYPE scx_attrname VALUE '',
attr3 TYPE scx_attrname VALUE '',
attr4 TYPE scx_attrname VALUE '',
END OF timeout,
BEGIN OF rate_limit_exceeded,
msgid TYPE symsgid VALUE 'Z_API',
msgno TYPE symsgno VALUE '004',
attr1 TYPE scx_attrname VALUE 'MV_RETRY_AFTER',
attr2 TYPE scx_attrname VALUE '',
attr3 TYPE scx_attrname VALUE '',
attr4 TYPE scx_attrname VALUE '',
END OF rate_limit_exceeded.
DATA:
mv_url TYPE string,
mv_status_code TYPE i,
mv_status_text TYPE string,
mv_retry_after TYPE i,
mv_is_retryable TYPE abap_bool.
METHODS constructor
IMPORTING
textid LIKE if_t100_message=>t100key OPTIONAL
previous LIKE previous OPTIONAL
iv_url TYPE string OPTIONAL
iv_status TYPE i OPTIONAL
iv_text TYPE string OPTIONAL
iv_retryable TYPE abap_bool DEFAULT abap_false.
METHODS is_retryable
RETURNING VALUE(rv_retryable) TYPE abap_bool.
ENDCLASS.
CLASS zcx_external_api_error IMPLEMENTATION.
METHOD constructor.
super->constructor( previous = previous ).
mv_url = iv_url.
mv_status_code = iv_status.
mv_status_text = iv_text.
mv_is_retryable = iv_retryable.
IF textid IS INITIAL.
if_t100_message~t100key = if_t100_message=>default_textid.
ELSE.
if_t100_message~t100key = textid.
ENDIF.
ENDMETHOD.
METHOD is_retryable.
rv_retryable = mv_is_retryable.
ENDMETHOD.
ENDCLASS.

Logique de retry avec Exponential Backoff

CLASS zcl_api_client_with_retry DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
CONSTANTS:
c_max_retries TYPE i VALUE 3,
c_initial_delay TYPE i VALUE 1000, " Millisecondes
c_max_delay TYPE i VALUE 30000. " Millisecondes
METHODS execute_with_retry
IMPORTING
io_client TYPE REF TO if_web_http_client
iv_method TYPE i DEFAULT if_web_http_client=>get
RETURNING
VALUE(ro_response) TYPE REF TO if_web_http_response
RAISING
zcx_external_api_error.
PRIVATE SECTION.
METHODS is_retryable_status
IMPORTING iv_status TYPE i
RETURNING VALUE(rv_retryable) TYPE abap_bool.
METHODS wait_with_backoff
IMPORTING iv_attempt TYPE i.
ENDCLASS.
CLASS zcl_api_client_with_retry IMPLEMENTATION.
METHOD execute_with_retry.
DATA lv_attempts TYPE i.
DATA lx_last_error TYPE REF TO zcx_external_api_error.
WHILE lv_attempts < c_max_retries.
lv_attempts = lv_attempts + 1.
TRY.
" Executer la requete
ro_response = io_client->execute( iv_method ).
DATA(lv_status) = ro_response->get_status( )-code.
" Reponse reussie
IF lv_status >= 200 AND lv_status < 300.
RETURN.
ENDIF.
" Rate Limit
IF lv_status = 429.
" Evaluer le header Retry-After
DATA(lv_retry_after) = ro_response->get_header_field( 'Retry-After' ).
wait_with_backoff( lv_attempts ).
CONTINUE.
ENDIF.
" Erreurs serveur (5xx) - retry
IF is_retryable_status( lv_status ).
IF lv_attempts < c_max_retries.
wait_with_backoff( lv_attempts ).
CONTINUE.
ENDIF.
ENDIF.
" Erreurs client (4xx) - pas de retry
RAISE EXCEPTION TYPE zcx_external_api_error
EXPORTING
textid = zcx_external_api_error=>http_error
iv_status = lv_status
iv_text = ro_response->get_status( )-reason
iv_retryable = abap_false.
CATCH cx_web_http_client_error INTO DATA(lx_http).
" Erreur reseau - retry
IF lv_attempts < c_max_retries.
wait_with_backoff( lv_attempts ).
CONTINUE.
ENDIF.
RAISE EXCEPTION TYPE zcx_external_api_error
EXPORTING
textid = zcx_external_api_error=>connection_failed
previous = lx_http
iv_retryable = abap_true.
ENDTRY.
ENDWHILE.
" Max Retries atteint
RAISE EXCEPTION TYPE zcx_external_api_error
EXPORTING
textid = zcx_external_api_error=>connection_failed
iv_retryable = abap_false.
ENDMETHOD.
METHOD is_retryable_status.
" Erreurs serveur 5xx et 429 Rate Limit
rv_retryable = xsdbool(
iv_status = 429 OR
iv_status = 500 OR
iv_status = 502 OR
iv_status = 503 OR
iv_status = 504
).
ENDMETHOD.
METHOD wait_with_backoff.
" Exponential Backoff : delay = initial_delay * 2^(attempt-1)
DATA(lv_delay) = c_initial_delay * ipow( base = 2 exp = iv_attempt - 1 ).
" Limiter au maximum
IF lv_delay > c_max_delay.
lv_delay = c_max_delay.
ENDIF.
" Attendre
cl_abap_session=>sleep( lv_delay ).
ENDMETHOD.
ENDCLASS.

Integration dans RAP

Determination avec appel API

CLASS lhc_order DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS calculate_shipping FOR DETERMINE ON SAVE
IMPORTING keys FOR Order~CalculateShipping.
ENDCLASS.
CLASS lhc_order IMPLEMENTATION.
METHOD calculate_shipping.
" Lire les commandes
READ ENTITIES OF zi_order IN LOCAL MODE
ENTITY Order
FIELDS ( ShippingAddress PostalCode Country Weight )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
" Appeler l'API de livraison externe
DATA(lo_shipping_api) = NEW zcl_shipping_api( ).
LOOP AT lt_orders INTO DATA(ls_order).
TRY.
" Recuperer les frais de livraison depuis le service externe
DATA(ls_shipping) = lo_shipping_api->calculate_shipping(
iv_country = ls_order-Country
iv_postal_code = ls_order-PostalCode
iv_weight = ls_order-Weight
).
" Mettre a jour la commande
MODIFY ENTITIES OF zi_order IN LOCAL MODE
ENTITY Order
UPDATE FIELDS ( ShippingCost EstimatedDelivery )
WITH VALUE #( (
%tky = ls_order-%tky
ShippingCost = ls_shipping-cost
EstimatedDelivery = ls_shipping-delivery_date
) ).
CATCH zcx_external_api_error INTO DATA(lx_error).
" Ajouter l'erreur comme message
APPEND VALUE #(
%tky = ls_order-%tky
%msg = new_message_with_text( text = lx_error->get_text( ) )
%element-ShippingCost = if_abap_behv=>mk-on
) TO reported-order.
ENDTRY.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Action avec integration API

CLASS lhc_product DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS refresh_stock FOR MODIFY
IMPORTING keys FOR ACTION Product~RefreshStock RESULT result.
ENDCLASS.
CLASS lhc_product IMPLEMENTATION.
METHOD refresh_stock.
" Lire les produits
READ ENTITIES OF zi_product IN LOCAL MODE
ENTITY Product
FIELDS ( ProductId ExternalId )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_products).
" Appeler l'API d'inventaire externe
DATA(lo_inventory_api) = NEW zcl_inventory_api( ).
" Requete batch pour tous les produits
DATA lt_product_ids TYPE string_table.
LOOP AT lt_products INTO DATA(ls_product).
APPEND ls_product-ExternalId TO lt_product_ids.
ENDLOOP.
TRY.
" Recuperer les niveaux de stock
DATA(lt_stock) = lo_inventory_api->get_stock_levels(
it_product_ids = lt_product_ids
).
" Mettre a jour les produits
LOOP AT lt_products INTO ls_product.
DATA(ls_stock) = VALUE #( lt_stock[ product_id = ls_product-ExternalId ] OPTIONAL ).
IF ls_stock IS NOT INITIAL.
MODIFY ENTITIES OF zi_product IN LOCAL MODE
ENTITY Product
UPDATE FIELDS ( StockQuantity LastStockUpdate )
WITH VALUE #( (
%tky = ls_product-%tky
StockQuantity = ls_stock-quantity
LastStockUpdate = utclong_current( )
) ).
ENDIF.
ENDLOOP.
" Retourner le resultat
READ ENTITIES OF zi_product IN LOCAL MODE
ENTITY Product
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_updated).
result = VALUE #( FOR wa IN lt_updated (
%tky = wa-%tky
%param = wa
) ).
CATCH zcx_external_api_error INTO DATA(lx_error).
LOOP AT keys INTO DATA(ls_key).
APPEND VALUE #(
%tky = ls_key-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = lx_error->get_text( )
)
) TO reported-product.
ENDLOOP.
ENDTRY.
ENDMETHOD.
ENDCLASS.

Bonnes pratiques

A FAIRE

RecommandationDescription
Communication ArrangementsGerer les credentials de maniere centralisee, jamais dans le code
Logique de retryExponential Backoff pour les erreurs transitoires
Definir les timeoutsConfigurer des timeouts appropries
Appeler close()Toujours fermer le HTTP Client (meme en cas d’erreur)
Gestion des erreursExceptions specifiques pour les erreurs API
LoggingJournaliser les appels API pour le debogage
Requetes batchPlusieurs enregistrements en un seul appel si possible

A NE PAS FAIRE

A eviterRaison
Credentials dans le codeRisque de securite, difficile a modifier
Retry illimitePeut surcharger le systeme
Appels longs synchronesBloque l’UI, risque de timeout
Erreurs ignoreesConduit a des donnees incoherentes
Validation manquanteToujours valider les reponses API

Conseils de performance

" 1. Reutilisation de connexion - Reutiliser le client
DATA: go_client TYPE REF TO if_web_http_client.
METHOD get_or_create_client.
IF go_client IS NOT BOUND.
DATA(lo_dest) = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_API"
service_id = 'Z_SERVICE"
).
go_client = cl_web_http_client_manager=>create_by_http_destination( lo_dest ).
ENDIF.
ro_client = go_client.
ENDMETHOD.
" 2. Batch au lieu de requetes individuelles
METHOD fetch_multiple_products.
" MAUVAIS : N requetes individuelles
LOOP AT it_product_ids INTO DATA(lv_id).
APPEND fetch_single( lv_id ) TO rt_products.
ENDLOOP.
" BON : Une requete batch
DATA(lv_ids) = concat_lines_of( table = it_product_ids sep = ',' ).
rt_products = fetch_batch( lv_ids ).
ENDMETHOD.
" 3. Cache pour les donnees statiques
CLASS-DATA: gt_cache TYPE STANDARD TABLE OF ty_product,
gv_cache_time TYPE timestamp.
METHOD get_products_cached.
" Cache valide 5 minutes
DATA(lv_now) = utclong_current( ).
DATA(lv_age) = cl_abap_tstmp=>subtract( tstmp1 = lv_now tstmp2 = gv_cache_time ).
IF gv_cache_time IS INITIAL OR lv_age > 300.
gt_cache = fetch_from_api( ).
gv_cache_time = lv_now.
ENDIF.
rt_products = gt_cache.
ENDMETHOD.

Depannage

ProblemeCause possibleSolution
401 UnauthorizedToken expire, credentials incorrectsVerifier le Communication Arrangement
403 ForbiddenPermissions manquantesVerifier le scope API
404 Not FoundChemin incorrectValider l’URL et le chemin
429 Too Many RequestsRate Limit atteintRespecter le header Retry-After
500 Server ErrorProbleme backendVerifier les logs, implementer le retry
Connection TimeoutReseau, FirewallVerifier le SAP Cloud Connector
SSL Certificate ErrorCertificat invalideConfigurer le Trust Store

Sujets connexes