A contract covers success and failure
- 01RequestIntent and data
- 02BoundaryPermissions and limits
- 03ResponseResult or error
- 04RetryCompatibility and effect
Across many integration reviews, I have seen the same cluster of choices: POST for reads and deletes, 200 OK for every outcome, field definitions in a separate spreadsheet, and no compatibility policy.
This is a composite example, but a recognisable one:
POST /api/client/get
POST /api/client/delete
POST /api/client/getStatus
Using POST is not forbidden. The problem is a contract that fails to explain intent, retry behaviour, errors, and the data lifecycle. Those were the parts I emphasised when teaching systems analysis.
API does not mean REST
| Approach | Interaction model | Contract | Useful when | Main cost |
|---|---|---|---|---|
| HTTP resource API | Resources and HTTP semantics | OpenAPI is a common choice | Public and internal web-facing integrations | Consistent conventions and evolution rules |
| SOAP | XML messages and operations | WSDL and XSD | Established enterprise and WS-* ecosystems | Specification and tooling complexity |
| GraphQL | Queries over a typed graph | GraphQL schema | Clients need different views of the same data | Resolver cost, query controls, governance |
| JSON-RPC | Method calls with parameters | Convention or external schema | Compact RPC interfaces and internal utilities | Little built-in discovery or evolution |
| gRPC | Typed remote procedures | .proto | Internal services, streaming, generated clients | Binary tooling and code-generation workflow |
REST is an architectural style, not a data encoding. Many production interfaces are more accurately described as JSON-over-HTTP APIs: they use HTTP methods, URIs, and status codes without implementing every REST constraint. That is fine when the contract is explicit.
HTTP semantics without shortcuts
HTTP is stateless in the sense that each request can be understood in isolation. A server can still store resources, sessions, and application state; it must not depend on hidden context associated with a particular connection.
Methods communicate intent:
GETretrieves a representation and has safe, idempotent semantics;POSTsubmits data to a resource for processing — creation is common but not its only use;PUTcreates or replaces the state of the target resource and is idempotent by intended effect;PATCHapplies a partial change and is not inherently idempotent;DELETEremoves the association with a resource and is idempotent by intended effect.
Do not force every procedure into a fake resource model. POST /risk-assessments can reasonably create an assessment result. A genuinely procedural interface may be clearer as JSON-RPC or gRPC.
Status codes are part of the contract as well:
200 OK: the request succeeded;201 Created: a resource was created, usually with aLocation;204 No Content: success with no response body;400 Bad Request: the request cannot be processed as submitted;401 Unauthorized: valid authentication credentials are missing;403 Forbidden: the server understood the request but refuses access;404 Not Found: the target resource was not found or is not disclosed;409 Conflict: the request conflicts with current state;500 Internal Server Error: the server encountered an unexpected condition.
Returning 200 for a processing failure that the contract defines as an HTTP error removes a standard signal from gateways, monitoring, and clients. A negative business outcome is different: a completed assessment can return 200 with a “not approved” decision in its body. The contract must distinguish successful execution from the business decision it produces. GraphQL has separate partial-response semantics and may return both data and errors; that convention should not be copied blindly into every JSON API.
SOAP is a messaging framework, not an automatic transaction
SOAP defines an XML envelope and message-processing model. WSDL and XSD provide mature operation and type contracts, which remains valuable where that ecosystem is already the integration standard.
WS-Security, WS-ReliableMessaging, and transaction-related extensions are separate specifications and profiles. SOAP alone does not switch on encryption, guaranteed delivery, or a distributed transaction. Those properties depend on the selected extensions, binding, implementation, and end-to-end design.
Choose SOAP for interoperability with an existing landscape or a specific WS-* requirement, not because “SOAP is reliable” in the abstract.
GraphQL trades client flexibility for governance
A GraphQL service publishes a typed schema, while each client selects the fields it needs. This works well when web, mobile, and internal applications require different views of the same entities.
The server takes on new responsibilities:
- resolvers can create N+1 query patterns;
- query depth and cost need limits;
- authorisation belongs at the business-object and field boundary;
- schema changes need a deprecation policy;
- performance cannot be judged by HTTP request count alone.
GraphQL commonly uses HTTP and JSON, but the language specification does not mandate one transport. Query operations can use GET, which enables HTTP caching, and persisted documents are another option. “GraphQL cannot be cached” is therefore too broad.
gRPC provides contracts and streaming, not magic latency
gRPC defines services and messages in .proto files, generates client and server code, and supports unary, client-streaming, server-streaming, and bidirectional-streaming calls. The common stack uses HTTP/2 and Protobuf by default, while the framework can support other content types.
It suits typed internal interfaces, provided the design covers deadlines, cancellation, retries, and schema evolution. The binary payload is less convenient to inspect directly, but tools such as grpcurl and server reflection make diagnosis practical.
No protocol guarantees a fixed latency improvement. Benchmark the real payload, libraries, network path, and call pattern. A browser-facing API also needs a decision about gRPC-Web or a gateway and must account for the capabilities of intermediaries.
How I choose an approach
Instead of ranking protocols, I answer these questions:
- Who consumes the API, and what can they support?
- Is the interaction naturally a resource operation, procedure call, or graph query?
- Is streaming or bidirectional exchange required?
- How will the contract evolve, and how many versions must coexist?
- Which proxies, gateways, and diagnostic tools sit on the path?
- What do measurements say about latency, payload size, and throughput?
- Who owns the interface after release?
Reliability is not selected by protocol name. Timeouts, retries, idempotency, backpressure, and data consistency require their own design.
Seven checks for an API specification
1. Operations and semantics
Is each operation clearly a read, command, or resource creation? Can a client retry safely after a timeout?
2. Errors
Does the response include stable machine codes, a useful message, a correlation ID, and a clear distinction between client and server failures?
3. Compatibility
A version in the URL is only one option. Media types, headers, or compatible evolution of one contract can also work. The important part is a policy for breaking changes and deprecation.
4. Pagination and limits
Large collections need bounds. Offset pagination is simple; a cursor over a stable ordering key can avoid some skips and duplicates as data changes. A cursor alone does not guarantee a consistent snapshot. Define maximum page size, deterministic tie-breaking and behaviour when data changes between requests.
5. Failure and retry behaviour
Specify timeouts, retry rules, idempotency keys for non-idempotent operations, and partial-success behaviour.
6. Data security
Document authentication, authorisation, sensitive fields, and rules that keep secrets out of URLs and logs.
7. Observability
Agree on request or correlation IDs, error and latency metrics, and ownership of alerts before production.
A practical Telegram bot exercise
In my course, students built a small Telegram bot with Flask. A webhook delivers a JSON POST; the application validates the update and sends a response through the Telegram Bot API.
That compact exercise covers methods, JSON, token handling, timeouts, errors, and repeat delivery of an update. API theory becomes concrete because every assumption is exercised by a real request.
A systems analyst does not need to memorise a technology catalogue. The essential skill is reading a specification and finding ambiguity before implementation. Date formats, nullable fields, page limits, and timeout retries look minor only until the first incompatible client ships.
For authoritative semantics, use RFC 9110, SOAP 1.2, GraphQL over HTTP, and the gRPC core concepts.
Original article: API From A to Z on Habr
Yours, DPUPP
Related Articles
AI in development: where it helps and where it creates new risk
A practical model-selection guide: 19 October 2026 API prices, self-hosting, task acceptance and the full cost of AI-assisted delivery.
Analyst Days 16: Behold the Path of Data, Padawan
A reconstruction of the main ideas from my Analyst Days 16 talk: how data gains context, why roles see the same dataset differently, and what an analyst should verify.
Analyst Days 14: Don't Paint the Grass — Data Risk in a BANI World
A reconstruction of my Analyst Days 14 talk on data quality and ownership: distinguishing a working control from attractive reporting.