Le Service Consumption Model (SCM) est la méthode recommandée pour consommer des APIs REST et OData externes de manière typée dans ABAP Cloud. Contrairement à l’appel direct du client HTTP, le SCM génère automatiquement des classes proxy ABAP et des types de données à partir de la spécification API - cela fait gagner du temps de développement et évite les erreurs.
Aperçu : SCM vs. Client HTTP
| Aspect | Service Consumption Model | Client HTTP direct |
|---|---|---|
| Typage | Complet - types générés | Aucun - traitement JSON manuel |
| Effort | Une fois : Import + Configuration | Chaque appel : Construire la requête, parser la réponse |
| Maintenabilité | Élevée - changements API visibles | Faible - erreurs uniquement à l’exécution |
| Flexibilité | Limitée aux APIs définies | Flexibilité maximale |
| Cas d’usage | APIs externes stables (OData, OpenAPI) | Appels ad-hoc, APIs dynamiques |
Quand choisir quelle approche ?
Utiliser le Service Consumption Model quand :
- Vous consommez une API OData ou REST stable
- L’API a une spécification EDMX ou OpenAPI
- Le typage et la maintenabilité sont importants
- Plusieurs opérations API sont utilisées
Utiliser le Client HTTP direct quand :
- L’API n’a pas de spécification formelle
- Vous n’avez besoin que de quelques appels simples
- L’API change fréquemment
- Vous avez besoin d’un contrôle maximal sur Request/Response
Pour les détails sur l’approche client HTTP directe, voir ABAP HTTP Client : Appeler des APIs REST.
Formats API supportés
Le Service Consumption Model supporte trois formats :
┌─────────────────────────────────────────────────────────────────────────┐│ Service Consumption Model - Formats supportés │├─────────────────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────┐ ││ │ OData V2 (EDMX) │ │ OData V4 (EDMX) │ │ OpenAPI 3.0 │ ││ │ │ │ │ │ (JSON/YAML) │ ││ │ - SAP Standard │ │ - OData moderne │ │ - APIs REST │ ││ │ - APIs S/4HANA │ │ - Services RAP │ │ - APIs externes│ ││ │ - SuccessFactors │ │ - Services BTP │ │ - APIs Cloud │ ││ └─────────────────────┘ └─────────────────────┘ └─────────────────┘ ││ ││ Import dans ADT : ││ File → New → Other ABAP Repository Object ││ → Connectivity → Service Consumption Model │└─────────────────────────────────────────────────────────────────────────┘Étape par étape : Créer un SCM
1. Obtenir la spécification API
D’abord, vous avez besoin du fichier EDMX ou OpenAPI de l’API cible :
APIs OData (EDMX) :
# SAP API Business Hubhttps://api.sap.com → Sélectionner API → API Specification → Download EDMX
# Depuis un système SAP en cours d'exécutionGET https://<host>/sap/opu/odata/sap/<SERVICE_NAME>/$metadataAPIs REST (OpenAPI) :
# APIs publiqueshttps://api.example.com/openapi.jsonhttps://api.example.com/swagger.json
# Services SAP BTPhttps://api.sap.com → Sélectionner Service → Download OpenAPI spec2. Créer le Service Consumption Model
Dans ADT (ABAP Development Tools) :
- Clic droit sur Package → New → Other ABAP Repository Object
- Catégorie : Connectivity → Service Consumption Model
- Remplir l’assistant :
| Champ | Exemple | Description |
|---|---|---|
| Name | ZSCM_WEATHER_API | Nom technique |
| Description | Weather API Consumer | Brève description |
| Remote Consumption Mode | OData ou Web Service | Type d’API |
- Importer le fichier de métadonnées (EDMX, OpenAPI JSON, ou WSDL)
- Finish - ADT génère tous les artefacts
3. Comprendre les artefacts générés
Après l’import, vous trouverez les objets suivants :
ZSCM_WEATHER_API (Service Consumption Model)│├── ZSCM_WEATHER_API_PROXY (Classe Proxy)│ ├── get_weather_forecast() " Opération de l'API│ ├── get_current_weather() " Opération de l'API│ └── create_alert() " Opération de l'API│├── ZS_WEATHER_FORECAST (Structure)│ ├── location TYPE string│ ├── temp_min TYPE decfloat16│ └── temp_max TYPE decfloat16│├── ZS_CURRENT_WEATHER (Structure)│ └── ...│└── ZCX_WEATHER_API (Classe Exception) └── Erreurs métier/techniquesExemple de code : Appel API avec proxy SCM
Prérequis : Communication Arrangement
Avant que le proxy ne fonctionne, vous avez besoin de la configuration de connexion. Voir Communication Scenarios Guide pour les détails.
Implémenter l’appel proxy
CLASS zcl_weather_service DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. TYPES: BEGIN OF ty_weather_result, location TYPE string, temperature TYPE decfloat16, humidity TYPE i, success TYPE abap_bool, error_msg TYPE string, END OF ty_weather_result.
METHODS get_weather IMPORTING iv_location TYPE string RETURNING VALUE(rs_result) TYPE ty_weather_result.
ENDCLASS.
CLASS zcl_weather_service IMPLEMENTATION.
METHOD get_weather. " Obtenir la destination via Communication Arrangement DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement( comm_scenario = 'Z_WEATHER_OUTBOUND" service_id = 'Z_WEATHER_API_REST" ).
" Instancier le proxy DATA(lo_proxy) = NEW zscm_weather_api_proxy( iv_destination = lo_destination ).
TRY. " Appel API typé - paramètres d'entrée comme structure DATA(ls_request) = VALUE zs_weather_request( location = iv_location units = 'metric" ).
" Appeler l'API - Response comme structure générée DATA(ls_response) = lo_proxy->get_current_weather( is_request = ls_request ).
" Mapper le résultat rs_result = VALUE #( location = ls_response-name temperature = ls_response-main-temp humidity = ls_response-main-humidity success = abap_true ).
CATCH zcx_weather_api INTO DATA(lx_api). " Erreur métier (ex. Location non trouvée) rs_result-success = abap_false. rs_result-error_msg = lx_api->get_text( ).
CATCH cx_http_dest_provider_error cx_web_http_client_error INTO DATA(lx_http). " Erreur technique (réseau, timeout) rs_result-success = abap_false. rs_result-error_msg = |Erreur de connexion : { lx_http->get_text( ) }|.
ENDTRY. ENDMETHOD.
ENDCLASS.Gestion des réponses et mapping
Utiliser les types automatiques
Le grand avantage du SCM : Vous travaillez avec des structures ABAP au lieu de chaînes JSON.
" SANS SCM - parsing JSON manuelDATA(lv_json) = lo_client->execute( )->get_text( )./ui2/cl_json=>deserialize( EXPORTING json = lv_json CHANGING data = ls_weather)." Sujet aux erreurs : les noms de champs doivent correspondre exactement
" AVEC SCM - typéDATA(ls_weather) = lo_proxy->get_current_weather( ls_request )." Le compilateur vérifie la structure, les noms de champs sont garantis correctsTraiter les réponses complexes
Pour les structures imbriquées, utilisez les types générés :
" Structure imbriquée générée" zs_forecast_response" ├── city: zs_city" │ ├── name" │ └── country" └── list: TABLE OF zs_forecast_item" ├── dt (timestamp)" ├── main: zs_main_data" │ ├── temp" │ └── humidity" └── weather: TABLE OF zs_weather_desc
DATA(ls_forecast) = lo_proxy->get_forecast( ls_request ).
" Accès aux données imbriquées - entièrement typéLOOP AT ls_forecast-list INTO DATA(ls_item). DATA(lv_temp) = ls_item-main-temp.
LOOP AT ls_item-weather INTO DATA(ls_desc). " Traiter les descriptions météo DATA(lv_description) = ls_desc-description. ENDLOOP.ENDLOOP.Différence : Client HTTP vs. SCM
| Scénario | Client HTTP | Service Consumption Model |
|---|---|---|
| Appeler l’API | URL + Method + Body manuellement | Méthode avec paramètres |
| Construire la requête | Sérialiser JSON | Remplir structure ABAP |
| Lire la réponse | Désérialiser JSON | Structure ABAP directe |
| Types d’erreurs | Vérifier codes statut HTTP | Exceptions spécifiques |
| Changement API | Erreur à l’exécution | Erreur de compilation |
Comparaison par l’exemple
" ══════════════════════════════════════════════════════════════════" Approche 1 : Client HTTP direct" ══════════════════════════════════════════════════════════════════DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination( lo_destination).
lo_client->get_http_request( )->set_uri_path( '/weather' ).lo_client->get_http_request( )->set_query_parameter( name = 'q" value = 'Berlin").
DATA(lo_response) = lo_client->execute( if_web_http_client=>get ).DATA(lv_json) = lo_response->get_text( ).
" Parser JSON manuellement - sujet aux erreursDATA: BEGIN OF ls_weather, name TYPE string, main TYPE REF TO data, END OF ls_weather.
/ui2/cl_json=>deserialize( EXPORTING json = lv_json CHANGING data = ls_weather).
lo_client->close( ).
" ══════════════════════════════════════════════════════════════════" Approche 2 : Service Consumption Model" ══════════════════════════════════════════════════════════════════DATA(lo_proxy) = NEW zscm_weather_api( lo_destination ).
" Appel typé - le compilateur valide les paramètresDATA(ls_weather) = lo_proxy->get_current_weather( VALUE #( q = 'Berlin' )).
" Accès direct aux champs typésDATA(lv_temp) = ls_weather-main-temp.Gestion des erreurs et bonnes pratiques
Comprendre la hiérarchie des exceptions
TRY. DATA(ls_result) = lo_proxy->get_data( ls_request ).
CATCH zcx_scm_business_error INTO DATA(lx_business). " Erreur métier - l'API a signalé une erreur (ex. 404, 422) " Celles-ci ne sont PAS réessayables CASE lx_business->http_status. WHEN 404. " Ressource non trouvée WHEN 422. " Erreur de validation dans la requête ENDCASE.
CATCH cx_http_dest_provider_error INTO DATA(lx_dest). " Erreur de destination - problème de configuration " Logging, mais pas de retry LOG-POINT ID zlog SUBKEY 'DEST_ERROR" FIELDS lx_dest->get_text( ).
CATCH cx_web_http_client_error INTO DATA(lx_http). " Erreur technique - réseau, timeout " Celles-ci PEUVENT être réessayables IF lx_http->error_type = if_web_http_client=>co_timeout. " Retry possible ENDIF.
ENDTRY.Implémenter une logique de retry
CONSTANTS: c_max_retries TYPE i VALUE 3, c_retry_delay TYPE i VALUE 1000. " ms
DATA: lv_attempt TYPE i VALUE 1.
WHILE lv_attempt <= c_max_retries. TRY. DATA(ls_result) = lo_proxy->call_api( ls_request ). EXIT. " Succès - sortir de la boucle
CATCH cx_web_http_client_error INTO DATA(lx_http). IF lx_http->error_type = if_web_http_client=>co_timeout AND lv_attempt < c_max_retries. " Attendre et réessayer cl_abap_session=>sleep( c_retry_delay * lv_attempt ). lv_attempt = lv_attempt + 1. ELSE. " Plus de retry possible RAISE EXCEPTION TYPE zcx_api_call_failed EXPORTING textid = zcx_api_call_failed=>api_unavailable previous = lx_http. ENDIF. ENDTRY.ENDWHILE.Checklist des bonnes pratiques
| Bonne pratique | Description |
|---|---|
| Toujours gérer les exceptions | Les proxys SCM peuvent lever diverses exceptions |
| Configurer les timeouts | Définir des valeurs appropriées dans le Communication Arrangement |
| Retry uniquement pour erreurs transitoires | Timeouts oui, erreurs 4xx non |
| Activer le logging | Journaliser les appels API pour le débogage |
| Ne jamais hardcoder les credentials | Utiliser les Communication Arrangements |
| Surveiller la version API | Attention aux breaking changes lors de la régénération du proxy |
Intégrer le SCM dans RAP
Custom Entity pour données externes
Si vous voulez afficher des données d’API externe dans une app Fiori :
" Définir CDS Custom Entity@EndUserText.label: 'Données météo externes"@ObjectModel.query.implementedBy: 'ABAP:ZCL_WEATHER_QUERY"define custom entity ZI_WeatherData{ key Location : abap.char(100); Temperature : abap.dec(5,2); Humidity : abap.int4; Description : abap.char(200); LastUpdated : abap.timestampl;}
" Implémentation Query avec SCMCLASS zcl_weather_query DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_rap_query_provider.ENDCLASS.
CLASS zcl_weather_query IMPLEMENTATION. METHOD if_rap_query_provider~select. " Lire les paramètres de filtre DATA(lt_filters) = io_request->get_filter( )->get_as_ranges( ).
" Proxy SCM pour appel API DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement( comm_scenario = 'Z_WEATHER_OUTBOUND" ).
DATA(lo_proxy) = NEW zscm_weather_api( lo_destination ).
" Appeler l'API TRY. DATA(ls_weather) = lo_proxy->get_current_weather( VALUE #( q = 'Berlin' ) ).
" Mapper au format Custom Entity DATA(lt_result) = VALUE ztt_weather_data( ( location = ls_weather-name temperature = ls_weather-main-temp humidity = ls_weather-main-humidity description = ls_weather-weather[ 1 ]-description lastupdated = utclong_current( ) ) ).
io_response->set_total_number_of_records( lines( lt_result ) ). io_response->set_data( lt_result ).
CATCH cx_root INTO DATA(lx_error). RAISE EXCEPTION TYPE zcx_rap_query_provider EXPORTING previous = lx_error. ENDTRY. ENDMETHOD.ENDCLASS.Pour plus de détails sur les APIs externes dans RAP, voir RAP External API Consumption.
Erreurs courantes et solutions
Problème : “No metadata found”
Symptôme : Impossible de créer le proxyCause : Le fichier EDMX/OpenAPI est défectueux ou incomplet
Solution :1. Valider la spécification API dans le navigateur (Swagger Editor)2. Vérifier les références manquantes ($ref)3. Pour OpenAPI : Version 3.0+ requiseProblème : “Destination not found”
Symptôme : Erreur runtime lors de l'appel proxyCause : Communication Arrangement manquant ou mal configuré
Solution :1. Ouvrir l'app Fiori "Communication Arrangements"2. Vérifier le Scenario-ID (doit correspondre au code)3. S'assurer du statut "Active"4. Vérifier le service_id dans le code (paramètre service_id)Problème : “Type mismatch in response”
Symptôme : Erreurs de type de données lors de l'accès aux champs ResponseCause : L'API a changé le schéma, mais le proxy n'a pas été mis à jour
Solution :1. Télécharger la nouvelle spécification API2. Ouvrir SCM dans ADT → Clic droit → "Update Service"3. Vérifier les structures générées4. Adapter le code appelantSujets connexes
- Communication Scenarios Guide - Configuration détaillée des destinations
- ABAP HTTP Client - Accès API direct sans SCM
- RAP External API Consumption - Intégrer des APIs dans les applications RAP
- OAuth 2.0 / JWT dans ABAP Cloud - Authentification pour APIs externes
- Consommer des services web SOAP - SCM pour SOAP/WSDL
Conclusion
Le Service Consumption Model est la méthode recommandée pour l’intégration d’APIs externes stables dans ABAP Cloud. La génération automatique de classes proxy et de types de données fait gagner du temps de développement, améliore la qualité du code et rend les changements d’API immédiatement visibles. Pour les scénarios simples ou dynamiques, le client HTTP direct reste une alternative valide.