GraphQL mit ABAP Cloud: API-Alternativen zu OData

kategorie
Integration
Veröffentlicht
autor
Johannes

GraphQL hat sich als moderne API-Alternative zu REST und OData etabliert. Aber wie sieht es mit der Unterstützung in ABAP Cloud aus? Dieser Artikel vergleicht GraphQL mit OData, zeigt den aktuellen Stand der SAP-Unterstützung und präsentiert praktische Workarounds für GraphQL-Szenarien.

Was ist GraphQL?

GraphQL ist eine von Facebook (Meta) entwickelte Query-Sprache für APIs. Im Gegensatz zu REST und OData definiert der Client exakt, welche Daten er benötigt – nicht der Server.

Kernkonzepte von GraphQL:

KonzeptBeschreibung
QueryDaten lesen (vergleichbar mit GET)
MutationDaten ändern (vergleichbar mit POST/PUT/DELETE)
SubscriptionEchtzeit-Updates via WebSocket
SchemaTypisierte API-Definition
ResolverServerseitige Daten-Logik

GraphQL Query-Beispiel

# Client fragt exakt die benötigten Felder an
query GetOrder {
order(id: "4711") {
orderId
customer {
name
email
}
items {
product {
name
price
}
quantity
}
totalAmount
}
}

Antwort: Nur die angefragten Felder werden zurückgegeben – keine überflüssigen Daten.

Vergleich: GraphQL vs OData

Beide Protokolle adressieren ähnliche Anforderungen, haben aber unterschiedliche Stärken:

AspektGraphQLOData
HerkunftFacebook/Meta (2015)Microsoft/SAP (2007)
Query-FlexibilitätSehr hoch (Client bestimmt Felder)Mittel ($select, $expand)
Mehrere RessourcenEine Query für mehrere EntitätenMehrere Requests oder $expand
Over-/UnderfetchingMinimal (präzise Abfragen)Möglich (feste Entitäten)
TypsystemStark typisiert (Schema)Stark typisiert (EDMX/CSDL)
CachingKomplex (POST-Requests)Einfach (GET + HTTP-Caching)
VersionierungSchema-EvolutionURI-Versionierung
SAP-SupportBegrenztNativ (RAP, Gateway)
ToolingGraphiQL, ApolloFiori Elements, Gateway
Batch-RequestsNativ (mehrere Queries)$batch-Endpoint
EchtzeitSubscriptionsKeine native Unterstützung

Vorteile von GraphQL

  1. Keine Over-Fetching: Client erhält nur benötigte Felder
  2. Keine Under-Fetching: Eine Query für komplexe, verschachtelte Daten
  3. Starkes Typsystem: Schema als Vertrag zwischen Client und Server
  4. Introspection: API ist selbstdokumentierend
  5. Echtzeit-Support: Subscriptions für Push-Benachrichtigungen

Vorteile von OData (im SAP-Kontext)

  1. Native SAP-Integration: RAP, Fiori Elements, Gateway
  2. HTTP-Caching: GET-Requests sind cachebar
  3. Etabliertes Tooling: Breite SAP-Unterstützung
  4. Standardisiert: OASIS-Standard mit SAP-Erweiterungen
  5. Batch-Support: $batch für Transaktionen

Aktueller Stand: GraphQL in SAP/ABAP Cloud (2026)

Stand Februar 2026 gibt es keine native GraphQL-Unterstützung in ABAP Cloud. SAPs strategische API-Technologie bleibt OData in Kombination mit dem ABAP RESTful Application Programming Model (RAP).

SAP BTP GraphQL-Optionen

Auf der SAP Business Technology Platform gibt es folgende Möglichkeiten:

OptionBeschreibungABAP-Integration
SAP GraphUnified API für SAP-ProdukteKonsumiert SAP-APIs, kein ABAP-Backend
Apollo FederationGraphQL Gateway auf BTPABAP als Datenquelle via OData
Custom GraphQL ServiceEigene Implementierung (Node.js/Java)Ruft ABAP Cloud APIs auf

SAP Graph (Beta)

SAP Graph ist SAPs Ansatz für eine einheitliche API-Schicht, die verschiedene SAP-Produkte zusammenführt. Es verwendet GraphQL-ähnliche Konzepte, ist aber primär für die Konsumierung von SAP-Daten gedacht – nicht für die Erstellung eigener GraphQL-Endpunkte in ABAP.

Workaround 1: GraphQL-Gateway auf BTP

Die empfohlene Architektur ist ein GraphQL-Gateway auf der SAP BTP, das ABAP Cloud OData-Services als Backend nutzt.

┌─────────────────────────────────────────────────────────┐
│ Client (Web/Mobile) │
│ │ │
│ GraphQL Query │
│ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ GraphQL Gateway (BTP) │ │
│ │ Node.js + Apollo Server │ │
│ └─────────────────────────────────────────────────┘ │
│ │ │
│ OData Requests │
│ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ ABAP Cloud (RAP Services) │ │
│ │ OData V4 Endpoints │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘

Apollo Server als GraphQL-Gateway

// srv/graphql-gateway.js (CAP/Node.js auf BTP)
const { ApolloServer, gql } = require('apollo-server-express');
const axios = require('axios');
// GraphQL Schema Definition
const typeDefs = gql`
type Order {
orderId: ID!
customerId: String
customer: Customer
totalAmount: Float
currency: String
items: [OrderItem]
}
type Customer {
customerId: ID!
name: String
email: String
}
type OrderItem {
itemId: ID!
productId: String
quantity: Int
product: Product
}
type Product {
productId: ID!
name: String
price: Float
}
type Query {
order(id: ID!): Order
orders(top: Int, skip: Int): [Order]
customer(id: ID!): Customer
}
`;
// Resolver: GraphQL -> OData Mapping
const resolvers = {
Query: {
order: async (_, { id }, { dataSources }) => {
// OData-Request an ABAP Cloud
const response = await dataSources.abapAPI.get(
`/sap/opu/odata4/sap/zorderservice/Orders('${id}')`
);
return response.data;
},
orders: async (_, { top = 10, skip = 0 }, { dataSources }) => {
const response = await dataSources.abapAPI.get(
`/sap/opu/odata4/sap/zorderservice/Orders?$top=${top}&$skip=${skip}`
);
return response.data.value;
}
},
Order: {
// Resolver für verschachtelte Daten
customer: async (order, _, { dataSources }) => {
const response = await dataSources.abapAPI.get(
`/sap/opu/odata4/sap/zorderservice/Customers('${order.customerId}')`
);
return response.data;
},
items: async (order, _, { dataSources }) => {
const response = await dataSources.abapAPI.get(
`/sap/opu/odata4/sap/zorderservice/Orders('${order.orderId}')/Items`
);
return response.data.value;
}
}
};

ABAP Cloud RAP Service (Backend)

Das ABAP Cloud Backend stellt weiterhin OData-Services bereit:

-- CDS View Entity für Orders
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Order'
define view entity Z_I_Order
as select from zorder
association [1..1] to Z_I_Customer as _Customer
on $projection.CustomerId = _Customer.CustomerId
association [0..*] to Z_I_OrderItem as _Items
on $projection.OrderId = _Items.OrderId
{
key order_id as OrderId,
customer_id as CustomerId,
total_amount as TotalAmount,
currency as Currency,
_Customer,
_Items
}
-- Service Definition
@EndUserText.label: 'Order Service'
define service Z_SD_Order {
expose Z_C_Order as Orders;
expose Z_C_Customer as Customers;
expose Z_C_OrderItem as OrderItems;
}

Workaround 2: Custom HTTP Endpoint in ABAP

Für einfache GraphQL-ähnliche Szenarien kann ein Custom HTTP Handler in ABAP Cloud implementiert werden. Dies ist nicht empfohlen für produktive Szenarien, zeigt aber die Machbarkeit.

CLASS zcl_graphql_handler DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_http_service_extension.
PRIVATE SECTION.
METHODS parse_query
IMPORTING iv_query TYPE string
EXPORTING ev_entity TYPE string
et_fields TYPE string_table.
METHODS execute_query
IMPORTING iv_entity TYPE string
it_fields TYPE string_table
RETURNING VALUE(rv_json) TYPE string.
ENDCLASS.
CLASS zcl_graphql_handler IMPLEMENTATION.
METHOD if_http_service_extension~handle_request.
DATA: lv_body TYPE string,
lv_entity TYPE string,
lt_fields TYPE string_table,
lv_result TYPE string.
" Request Body lesen (vereinfachtes GraphQL-Parsing)
lv_body = request->get_text( ).
" Query parsen (stark vereinfacht)
parse_query(
EXPORTING iv_query = lv_body
IMPORTING ev_entity = lv_entity
et_fields = lt_fields ).
" Daten abfragen
lv_result = execute_query(
iv_entity = lv_entity
it_fields = lt_fields ).
" Response
response->set_text( lv_result ).
response->set_header_field(
i_name = 'Content-Type'
i_value = 'application/json' ).
ENDMETHOD.
METHOD parse_query.
" Vereinfachtes Parsing - produktiv würde ein Parser benötigt
" Beispiel: { orders { orderId totalAmount } }
" ...
ENDMETHOD.
METHOD execute_query.
" Dynamische Feldauswahl basierend auf GraphQL-Query
" In der Praxis: CDS View mit dynamischer Projektion
" ...
ENDMETHOD.
ENDCLASS.

Einschränkungen:

  • Kein echtes GraphQL-Parsing
  • Keine Subscription-Unterstützung
  • Kein Standard-Tooling (GraphiQL)
  • Wartungsaufwand

Code-Vergleich: GraphQL vs OData

Szenario: Bestellung mit Kunde und Artikeln laden

GraphQL (eine Query):

query GetOrderWithDetails {
order(id: "4711") {
orderId
totalAmount
customer {
name
email
}
items {
quantity
product {
name
price
}
}
}
}

OData (mit $expand):

GET /Orders('4711')?$select=OrderId,TotalAmount
&$expand=Customer($select=Name,Email),
Items($select=Quantity;$expand=Product($select=Name,Price))

ABAP Cloud HTTP Client für OData:

" OData-Request mit $expand
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_OUTBOUND_ODATA'
service_id = 'Z_ODATA_SERVICE' ) ).
DATA(lo_request) = lo_client->get_http_request( ).
lo_request->set_uri_path(
'/sap/opu/odata4/sap/zorderservice/Orders(''4711'')' &&
'?$expand=Customer,Items($expand=Product)' ).
DATA(lo_response) = lo_client->execute( i_method = if_web_http_client=>get ).
DATA(lv_json) = lo_response->get_text( ).
" JSON parsen
/ui2/cl_json=>deserialize(
EXPORTING json = lv_json
CHANGING data = ls_order ).

Wann GraphQL, wann OData?

GraphQL bevorzugen bei:

SzenarioBegründung
Mobile AppsBandbreiten-Optimierung durch präzise Queries
Komplexe UIsViele verschachtelte Daten in einem Request
Echtzeit-AnforderungenSubscriptions für Live-Updates
Nicht-SAP FrontendReact/Vue/Angular mit Apollo Client
API-AggregationMehrere Backends über ein Gateway

OData bevorzugen bei:

SzenarioBegründung
SAP FioriNative Fiori Elements-Integration
ABAP Cloud nativeRAP-basierte Services ohne Middleware
Einfaches CachingHTTP GET-Requests
SAP-Standard-KonsumptionS/4HANA APIs, BTP Services
Batch-Operationen$batch für Transaktionen

Integration: GraphQL-Client in ABAP Cloud

Wenn ein externes System GraphQL anbietet, kann ABAP Cloud als GraphQL-Client fungieren:

CLASS zcl_graphql_client DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS execute_query
IMPORTING iv_query TYPE string
iv_variables TYPE string OPTIONAL
RETURNING VALUE(rv_response) TYPE string
RAISING cx_web_http_client_error.
ENDCLASS.
CLASS zcl_graphql_client IMPLEMENTATION.
METHOD execute_query.
" GraphQL-Request bauen
DATA(lv_body) = |\{"query": "{ iv_query }"|.
IF iv_variables IS NOT INITIAL.
lv_body = lv_body && |, "variables": { iv_variables }|.
ENDIF.
lv_body = lv_body && |\}|.
" HTTP Client erstellen
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_GRAPHQL_OUTBOUND'
service_id = 'GRAPHQL_API' ) ).
DATA(lo_request) = lo_client->get_http_request( ).
lo_request->set_uri_path( '/graphql' ).
lo_request->set_header_field(
i_name = 'Content-Type'
i_value = 'application/json' ).
lo_request->set_text( lv_body ).
" POST-Request ausführen
DATA(lo_response) = lo_client->execute( i_method = if_web_http_client=>post ).
rv_response = lo_response->get_text( ).
lo_client->close( ).
ENDMETHOD.
ENDCLASS.

Verwendung:

DATA(lo_gql) = NEW zcl_graphql_client( ).
DATA(lv_query) = |query \{ user(id: "123") \{ name email \} \}|.
TRY.
DATA(lv_result) = lo_gql->execute_query( lv_query ).
" JSON-Response verarbeiten...
CATCH cx_web_http_client_error INTO DATA(lx_error).
" Fehlerbehandlung
ENDTRY.

Fazit und Empfehlung

GraphQL ist nicht nativ in ABAP Cloud verfügbar – und das ist auch nicht SAPs strategische Richtung. OData bleibt die primäre API-Technologie für SAP-Systeme.

Dennoch gibt es valide GraphQL-Szenarien:

  1. Frontend-getriebene Anforderungen: Wenn React/Vue-Teams mit Apollo arbeiten
  2. API-Aggregation: Mehrere Backends über ein einheitliches Gateway
  3. Mobile Optimierung: Bandbreiten-sensitive Anwendungen
  4. Nicht-SAP Integration: Wenn Drittsysteme GraphQL erfordern

Empfohlene Architektur:

  • ABAP Cloud stellt OData-Services bereit (RAP)
  • GraphQL-Gateway auf BTP (Node.js/Apollo) transformiert Queries
  • Clients kommunizieren über GraphQL mit dem Gateway

Diese Architektur kombiniert die Stärken beider Welten: SAPs bewährte OData-Integration im Backend und GraphQLs Flexibilität für moderne Frontends.

Weiterführende Artikel: