23.03.2026
0
Beğenme
0
Görüntülenme
The building looked finished from a distance.
The structure was there.
Floors aligned.
Walls in place.
But inside, nothing actually worked yet.
Some APIs feel exactly like this.
The schema is correct.
The documentation is complete.
Swagger looks beautiful.
And still integration turns into a conversation.
“What does this error mean?”
“Should we retry?”
“Can the user fix this?”
“Why is this sometimes null?”
Nothing is technically broken.
But nothing is predictable either.
This is the difference between a correct API and a usable one.
On paper, everything checks out.
Clear endpoints.
Typed schemas.
Documented status codes.
The backend satisfies the specification.
The frontend still struggles to use it.
Because correctness answers what happened.
Clients need to know what to do next.
When that information is missing, the frontend doesn’t integrate your API — it reverse-engineers it.
From the backend perspective:
“The API is documented. Just follow the contract.”
From the frontend perspective:
“I don’t know what will happen when this fails.”
The gap appears outside the happy path.
A field exists but is it always required?
A request fails is it retryable?
An error appears should we redirect, show a message, or wait?
The backend sees valid responses.
The frontend sees decisions without information.
An API is not only a data interface.
It is a decision interface.
// Bad Example
{
"message": "Something went wrong"
}
// Bad Example
{
"error": "Invalid request"
}
These responses technically indicate failure but they communicate nothing.
From the frontend’s perspective:
The client doesn’t know if the user typed a wrong value, the session expired, the database timed out, or the service is temporarily unavailable.
So the frontend does the only possible thing:
show a generic toast and hope the user tries again.
Generic errors don’t simplify APIs. They outsource complexity to everyone else.
An error response isn’t just “bad news”.
It’s a behavior contract between backend and frontend.
If the backend only sends a message, the frontend still has to guess:
But if the backend sends a stable error code, the frontend can turn errors into predictable UX.
When errors are designed as decisions, the client becomes simple. When errors are only messages, the client becomes a detective.
// Typical Response
{ "success": true }
Looks clean. Does nothing.
The frontend learns exactly one thing: the request didn’t fail right now.
But what does the user see next? Can they continue? Should we refresh data? Was anything actually created?
// Human-friendly response
{
"status": "PENDING",
"nextAction": "POLL_PAYMENT",
"retryAfter": 2000
}
Now the client has a plan.
Instead of guessing UI behavior, the frontend can:
retryAfterGood APIs don’t just report results. They communicate intent.
The most common advice in API design:
“Just use proper HTTP status codes.”
Good practice — but not sufficient.
In real systems:
400 can mean ten different things409 is a conflict… but what kind?422 failed validation… can the user fix it or should we retry?HTTP codes categorize failures for machines and intermediaries — caching, proxies, monitoring. But the frontend still doesn’t know what to do.
Two completely different UI behaviors can share the same status code:
show inline validation vs retry silently vs redirect to login.
Status codes tell you that something went wrong. They don’t tell you how to recover.
HTTP codes classify errors. They don’t explain them.
A poorly designed API doesn’t just annoy developers it reshapes the entire system around uncertainty.
Frontend teams start hardcoding assumptions. Different screens interpret the same response differently. Workarounds slowly become “business logic”.
Now you have:
Support tickets increase because users see confusing states.
Developers slow down because every feature begins with reverse-engineering behavior.
The API didn’t fail technically. It failed organizationally.
Bad APIs don’t crash systems. They quietly tax every future feature.
We stopped designing responses as text — and started designing them as behavior.
1. Message → Code
Human-readable messages became optional. Stable error codes became mandatory.
Instead of parsing strings like “user already exists”, the client now reacts to EMAIL_ALREADY_EXISTS. Localization moved to the frontend. Logic moved out of guesswork.
2. Data → Next Action
Endpoints don’t just return data anymore they return the next step.
nextAction, status, and retry hints made async flows predictable instead of implicit. The UI no longer infers system state; it follows it.
3. Unknown → Predictable Categories
Every error belongs to a known category: user-fixable, retryable, or fatal.
The frontend can decide behavior without asking backend developers.
We didn’t change the transport layer. We changed the conversation.
An API is a user interface — just not for end users, but for developers. A clean schema and valid status codes may satisfy the backend, yet still leave the frontend guessing. Error responses shouldn’t exist merely to be read; they should drive behavior. When intent isn’t communicated, the client invents it, and every guess becomes long-term complexity. In the end, integration pain is rarely caused by missing endpoints — it’s caused by missing decisions. And that uncertainty is owned not by the consumer of the API, but by the one who designs it.
Kullanıcı yorumlarını görüntüleyebilmek için kayıt olmalısınız!
Kader Kaya
1 yıl deneyime sahip bir Backend Developer olarak Node.js, TypeScript ve MongoDB kullanarak ölçeklenebilir ve güvenli web uygulamaları geliştiriyorum. RESTful API tasarımı, JWT tabanlı kimlik doğrulama, rol bazlı yetkilendirme (RBAC), ödeme entegrasyonları ve Swagger/OpenAPI dokümantasyonu konularında deneyimliyim. Temiz mimari, mikroservis yapıları ve sürdürülebilir, test edilebilir sistemler geliştirmeye önem veriyorum. GDG topluluğundaki aktif rolüm sayesinde ekip çalışması ve iletişim becerilerimi de sürekli geliştiriyorum.
Konum
Antalya, TR
Eğitim
Bilgisayar Mühendisliği - Antalya Bilim Üniversitesi