API Literacy — Foundations
A practical guide to understanding APIs, contracts, and SAP context.
What is an API?
An API (Application Programming Interface) is just a way for two systems to talk to each other. Your phone app talks to a server via API. SAP talks to a bank via API. Even when you log in with Google, that's an API call happening behind the scenes.
You don't need to know what’s inside the system. You just know the “menu” of what it offers. Like in a restaurant — you don't enter the kitchen, you just order “Pizza” and expect pizza back.
API First Mindset
Normally, people build systems first and then later think: “Oh, we also need integration.” That's painful. API First flips it:
You start by asking: what should other people, apps, or systems be able to do with my app? You design the API first — the “contract” — before you write any logic. Then the backend, frontend, and even partners can all work against the same contract. This makes projects faster, cleaner, and easier to integrate.
Example (SAP flavored 🍵):
- Imagine a coffee producer running SAP S/4HANA.
- Old style: they’d build a sales order screen, then later add some custom RFCs or IDocs to integrate.
- API First style: they say “creating a sales order” is an API from the start.
- Endpoint: /sales-orders
- Method: POST
- Input: JSON with customer, product, quantity
- Output: confirmation number
- Now mobile apps, web portals, and partner systems all use the same API to create orders. One definition, many consumers.
API Contract — What it Really Means
When we say “API contract,” we mean a formal agreement between provider and consumer on how they communicate. It’s like a legal contract, but for data exchange.
What’s inside an API contract?
- Endpoints — URLs where the service is available. Example: /sales-orders/{id}
- Operations (HTTP Methods): GET (read), POST (create), PUT/PATCH (update), DELETE (remove)
- Request format — data structure the client must send (JSON, XML, OData payload)
- Response format — what comes back (fields, types, structure)
- Error handling — how errors look (status codes, error messages)
- Authentication & authorization — how to prove you’re allowed to call (OAuth, API key, JWT)
- Performance rules / limits — like pagination, rate limits, batch processing
If the provider changes the contract without notice, everything breaks. That’s why stability and versioning are core principles.
Principles of a Good API Contract
- Consistency: Same naming, same logic across endpoints. Example:
/customers/123/orders
not/custOrderData
. - Predictability: Errors follow a pattern, responses always structured.
- Discoverability: Clear documentation (OpenAPI, OData metadata).
- Versioning: Never break old consumers — add /v2/ when needed.
- Minimalism: Return only what’s needed. Avoid bloated responses.
- Security: Data protected with HTTPS, OAuth2, role checks.
Operations (CRUD)
Almost every API boils down to CRUD operations:
Operation | HTTP Method | Example (Sales Orders) |
---|---|---|
Create | POST | POST /sales-orders → create new order |
Read | GET | GET /sales-orders/123 → get order details |
Update | PATCH/PUT | PATCH /sales-orders/123 → change delivery date |
Delete | DELETE | DELETE /sales-orders/123 → cancel order |
That's the “universal language” across APIs.
OData V4 — The SAP Flavor of API Contracts
OData (Open Data Protocol) is Microsoft-born, SAP-adopted. It's basically REST + conventions. Think of it as a standardized way to describe and query business data over HTTP.
SAP uses it massively in S/4HANA, Fiori, BTP.
Key ideas in OData V4:
- Entity sets = tables/collections (like SalesOrders).
- Entities = single record (like SalesOrders('500001')).
- Metadata document = machine-readable contract ($metadata) describing all entities, fields, relationships, operations.
- Query options (the real power):
$filter
→GET /SalesOrders?$filter=Customer eq '1000'
$select
→ pick only fields you need$expand
→ include related entities (like header + items)$orderby
,$top
,$skip
→ pagination and sorting
Functions & Actions:
- Functions = pure, read-only operations (e.g., GetCreditLimit)
- Actions = side-effect operations (e.g., ReleaseOrder)
Batch requests allow sending multiple operations in one HTTP call, useful in SAP for performance.
Conformance levels: V4 is stricter and lighter than V2 — better JSON, cross-service consistency, async pattern support.
Why it matters in SAP world:
- Every Fiori app you open is powered by an OData API.
- Integration on BTP often relies on OData services from S/4.
- API First with OData means you model business objects as APIs before coding.
So when you hear “API contract in SAP context,” it usually means an OData metadata document ($metadata
) plus the CRUD operations exposed on entities.
API Design Process
Think of it like architecture:
- Identify the business object — Sales Order, Customer, Invoice.
- Define use cases — create order, change date, get details.
- Model resources (entities) — /sales-orders, /customers.
- Assign methods — POST for creation, GET for retrieval, etc.
- Design request/response formats — which fields, data types, mandatory vs optional.
- Define errors — if credit check fails, if customer not found, etc.
- Secure it — authentication (OAuth2), authorization (roles).
- Versioning strategy — how you’ll handle changes later.
How to Describe APIs
There are standards to make API contracts clear and shareable:
- OpenAPI (Swagger): The most popular format to describe REST APIs. Machine-readable (YAML/JSON) → generates docs, mock servers, test stubs.
- OData metadata (
$metadata
): Auto-generated contract in XML. Lists entities, properties, relationships. - AsyncAPI: Like OpenAPI, but for event-driven APIs (Kafka, AMQP, Event Mesh). Important if you go deeper into Event-Driven Architecture (SAP Event Mesh, Kafka).
Design Principles You Must Remember
- Resource orientation: Think nouns, not verbs (
/customers
, not/getCustomer
). - Statelessness: Each request is independent, no hidden state.
- Error standards: Always return proper HTTP codes (400, 401, 404, 500).
- Pagination: Never return “all” data; use
$skip
,$top
, or?page=
. - Filtering & searching: Use query params (
$filter
,?status=open
). - Extensibility: Allow custom fields without breaking core (SAP uses “extension fields”).
Design Tools & Documentation
- Stoplight Studio / Swagger Editor — for OpenAPI design.
- SAP API Business Hub — shows you how SAP describes APIs.
- Postman — test, mock, share APIs.
API Contracts in Event-Driven Architecture (EDA)
In REST/OData, the contract is about requests and responses. In EDA, the contract is about events and subscriptions.
Think of it as:
- REST = you call a taxi.
- Events = you stand outside, and when a taxi becomes available, it honks.
EDA Contract Basics
An EDA API contract usually describes:
- Event name/topic — e.g., SalesOrder.Created, Customer.Changed.
- Payload structure — what fields are inside the event (JSON, Avro, etc.).
- Producer — which system publishes the event.
- Consumers — who can subscribe.
- Delivery semantics — at least once, exactly once, etc.
- Protocol — Kafka, AMQP, MQTT, or SAP Event Mesh.
- Error handling — what happens if a consumer is down.
How to Describe Event APIs
AsyncAPI is the standard (like OpenAPI, but for events).
asyncapi: 2.5.0
info:
title: Sales Order Events
version: '1.0.0'
channels:
sales-order/created:
subscribe:
message:
name: SalesOrderCreated
payload:
type: object
properties:
id:
type: string
customer:
type: string
amount:
type: number
This acts as the contract between publisher (S/4HANA, MDG) and consumer (portal, BTP app, Kafka service).
EDA Design Principles
- Event as a fact, not a command: Good: SalesOrder.Created describes something that happened. Bad: CreateSalesOrder is a command (belongs in REST API).
- Schema stability: Never remove fields. Only add optional fields.
- Decoupling: Producer doesn't know who consumes. Consumer decides what to do.
- Granularity: Don't flood with tiny events, don't lump everything into “mega events.” Balance matters.
- Replayability: Events should be durable — you can replay them to rebuild state (Kafka strength).
EDA in SAP Context
- SAP S/4HANA publishes Business Events (via Enterprise Event Enablement).
- SAP Event Mesh (BTP service) routes these to consumers (internal apps, partners).
- SAP Advanced Event Mesh — enterprise-scale (Kafka-like backbone).
Typical examples:
- BusinessPartner.Changed — MDG publishes when BP master data updated.
- SalesOrder.Created — order service emits event, warehouse and billing apps react.
- Material.InventoryLow — triggers replenishment process.
Operations vs Events
REST/OData (Sync) | Events/EDA (Async) |
---|---|
Client asks server | Server notifies clients |
Request → Response | Event → Multiple Consumers |
CRUD operations | Publish/Subscribe |
Contract: OpenAPI/OData | Contract: AsyncAPI/Event Schema |
API Contracts Explained
1. REST (synchronous)
👉 Typical for modern apps.
Request (client → server):
POST /api/orders
Content-Type: application/json
{
"customerId": "C123",
"items": [
{"productId": "P1", "qty": 2},
{"productId": "P2", "qty": 1}
]
}
Response (server → client):
201 Created
{
"orderId": "O9876",
"status": "Accepted",
"total": 120.50,
"currency": "EUR"
}
Contract (OpenAPI snippet):
paths:
/orders:
post:
summary: Create a new order
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
customerId:
type: string
items:
type: array
items:
type: object
properties:
productId: { type: string }
qty: { type: integer }
responses:
"201":
description: Order created
2. OData (SAP style, synchronous)
👉 OData = REST + metadata (used in SAP S/4HANA).
Request:
POST /sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder
Content-Type: application/json
{
"SalesOrderType": "OR",
"SalesOrganization": "1000",
"DistributionChannel": "10",
"OrganizationDivision": "00",
"SoldToParty": "C123",
"SalesOrderItem": [
{
"Material": "P1",
"RequestedQuantity": "2"
},
{
"Material": "P2",
"RequestedQuantity": "1"
}
]
}
Response:
{
"SalesOrder": "50000123",
"OverallDeliveryStatus": "Not Delivered",
"OverallBillingStatus": "Not Billed"
}
3. SOAP (synchronous or async)
👉 Old enterprise standard, still common in SAP A2A/B2B.
Request (XML):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ord="http://example.com/order">
<soapenv:Header/>
<soapenv:Body>
<ord:CreateOrderRequest>
<CustomerId>C123</CustomerId>
<Items>
<Item>
<ProductId>P1</ProductId>
<Quantity>2</Quantity>
</Item>
<Item>
<ProductId>P2</ProductId>
<Quantity>1</Quantity>
</Item>
</Items>
</ord:CreateOrderRequest>
</soapenv:Body>
</soapenv:Envelope>
Response (XML):
<CreateOrderResponse>
<OrderId>O9876</OrderId>
<Status>Accepted</Status>
<Total>120.50</Total>
</CreateOrderResponse>
Contract (WSDL): defines request/response message formats, operations, and endpoints.
4. Async Event (Kafka, EDA)
👉 Fire-and-forget. Client doesn't wait for final result.
Producer (frontend or integration) publishes:
{
"eventType": "Order.CreateRequested",
"orderId": "tmp-12345",
"customerId": "C123",
"items": [
{"productId": "P1", "qty": 2},
{"productId": "P2", "qty": 1}
]
}
Consumer (order service) processes, then emits new event:
{
"eventType": "Order.Created",
"orderId": "O9876",
"status": "Accepted",
"total": 120.50
}
Contract (AsyncAPI snippet):
channels:
order/create:
publish:
message:
payload:
type: object
properties:
customerId: { type: string }
items:
type: array
items:
type: object
properties:
productId: { type: string }
qty: { type: integer }
5. Key takeaway
“An API contract is the agreement: what request looks like, what response or event looks like. For synchronous calls we use REST (OpenAPI) or OData in SAP, sometimes SOAP (WSDL). For asynchronous flows we use event-driven standards like Kafka with AsyncAPI. A simple example is Create Order: frontend sends order details, backend returns orderId and status — and both sides rely on the same contract to avoid breaking.”