RESTful APIs are everywhere. They’re the backbone of modern web and mobile applications, quietly orchestrating data exchange between clients and servers. But here’s the problem: many APIs claim to be RESTful without actually adhering to REST principles. The result? Inconsistent designs, confusing URIs, unpredictable behavior, and poor developer experience.
This post dives deep into the most common mistakes developers make when designing RESTful APIs — not just in theory, but through real-world examples. You’ll learn how to identify anti-patterns and refactor them into scalable, consistent, and intuitive interfaces. Whether you’re building APIs from scratch or improving legacy endpoints, these insights will guide you toward building APIs that developers will love to use.
Let’s take a closer look at the hidden pitfalls of REST and how to avoid them — one best practice at a time.

📌 Table of Contents
- 1. The RESTful Illusion
- 2. What Does RESTful API Really Mean?
- 3. 8 Common Mistakes in RESTful API Design
- 3.1 Using Verbs Instead of Resources
- 3.2 Misusing HTTP Methods
- 3.3 Inconsistent URI Structures
- 3.4 Ignoring or Misusing HTTP Status Codes
- 3.5 Over-Nesting of Resource URIs
- 3.6 Poor Handling of Filtering, Sorting, and Pagination
- 3.7 Unstructured or Unhelpful Error Responses
- 3.8 No Versioning Strategy
- 4. Case Study: Refactoring a Poorly Designed API
- 5. RESTful API Best Practices
- 6. Conclusion: An API Is a Contract
1. The RESTful Illusion
“We follow RESTful API principles.”
It’s a statement you’ll often hear from development teams. But when you actually inspect their APIs, you’ll find endpoints like /getUser
or /deleteComment
, all using POST for every operation, and returning 200 OK
for every response — even on errors.
This is the RESTful illusion. Just because you’re using HTTP doesn’t mean you’re building RESTful APIs. REST is not about using verbs in your URLs or exposing database operations over HTTP. It’s about resource-centric design, consistency, and leveraging HTTP semantics to communicate effectively.
In reality, many teams are building RPC-style APIs while labeling them as RESTful. This leads to brittle interfaces, poor documentation, and painful onboarding for developers. If your API doesn’t reflect clear resource structures, proper use of HTTP methods, and meaningful status codes, it’s time for a rethink.
In this post, we’ll break down what truly makes an API RESTful. You’ll learn the most common pitfalls — the silent productivity killers — and discover how to transform broken designs into elegant, predictable, and well-documented APIs.
Because a truly RESTful API doesn’t just work — it teaches itself. It’s scalable, maintainable, and most of all, respectful of the developers who use it.
2. What Does RESTful API Really Mean?
REST — short for Representational State Transfer — is more than a buzzword. Introduced by Roy Fielding in his 2000 Ph.D. dissertation, REST is an architectural style that defines a set of constraints for designing scalable, stateless, and cacheable systems — primarily on the web.
A RESTful API, then, is one that adheres to the principles of REST. But here’s the catch: many so-called “RESTful” APIs only superficially adopt its ideas. Simply using HTTP does not make your API RESTful. The true essence lies in **how resources are modeled**, **how HTTP methods are used**, and **how interactions are structured**.
✅ Core Elements of a RESTful API
- Resources: Everything exposed by your API should be modeled as a resource — a noun, not a verb. (e.g.,
/users
,/orders
) - Representations: Resources are returned in standard formats such as JSON or XML.
- HTTP Methods: Each action uses the proper verb: GET to read, POST to create, PUT/PATCH to update, DELETE to remove.
- Status Codes: The server communicates results with standard HTTP status codes, not just generic success or error messages.
- Statelessness: Every request contains all the context the server needs. Sessions are discouraged.
🚫 A Non-RESTful API Example
GET /getUserById?id=123
The example above is clearly not RESTful. It uses a verb (getUserById
) in the URI, relies on query parameters for what should be a resource identifier, and obscures the intent of the operation.
✅ A RESTful Alternative
GET /users/123
This version follows RESTful conventions. It treats “users” as a resource, and identifies the specific user with an ID in the URI path. The HTTP method (GET) implies that the operation is a read.
Why does this matter? Because RESTful design makes APIs **predictable**, **self-documenting**, and **easy to consume**. Developers can guess how an endpoint behaves without reading the documentation. This reduces cognitive load and speeds up integration.
In summary, REST is not a protocol or a standard — it’s a **philosophy for designing APIs** that are simple, scalable, and understandable. And the first step toward embracing REST is to stop thinking in terms of functions and start thinking in terms of resources.
3. 8 Common Mistakes in RESTful API Design
3.1 Using Verbs Instead of Resources
One of the most frequent mistakes in RESTful API design is treating the API like a collection of remote procedure calls (RPC). Developers often embed actions — not resources — in the URI, turning endpoints into function calls rather than resource representations.
🚫 Bad Example: Verb-Centric URIs
GET /getUser
POST /createOrder
PUT /updateProfile
DELETE /deleteComment
These URIs violate REST principles by describing what to do rather than what is being accessed. The use of verbs (get
, create
, update
, delete
) reveals an RPC mindset, not a resource-oriented one.
RESTful APIs, in contrast, use URIs to represent nouns — the resources — and let the HTTP methods (verbs) define the action. This allows your API to become predictable and consistent.
✅ Good Example: Resource-Centric URIs
GET /users/123
POST /orders
PUT /users/123/profile
DELETE /comments/456
Each URI now represents a specific resource or collection. The HTTP method defines the operation:
GET /users/123
– Retrieve user with ID 123POST /orders
– Create a new orderPUT /users/123/profile
– Update a user’s profileDELETE /comments/456
– Delete comment with ID 456
📌 Side-by-Side Comparison
Aspect | Verb-Centric (Non-RESTful) | Resource-Centric (RESTful) |
---|---|---|
URI | /getUser | /users/123 |
Intent | Action-driven | Resource-focused |
Flexibility | Low (Hard to generalize) | High (Scales well with resources) |
🧠 Key Takeaway
In RESTful API design, your URIs should always represent what the client is interacting with, not how the server performs it. Think in terms of “resources” instead of “operations,” and let HTTP methods do the talking.
3.2 Misusing HTTP Methods
HTTP methods are not arbitrary. In RESTful API design, they serve a clear and specific purpose — defining how a client intends to interact with a resource. But many APIs misuse these methods, either out of habit or due to a lack of understanding of their semantics.
Using the wrong method can lead to unexpected behavior, broken client applications, and security concerns. Let’s look at some common examples.
🚫 Bad Example: Incorrect Use of HTTP Methods
GET /deleteUser?id=123
POST /getUserInfo
DELETE /logout
In this example:
GET
is used to delete data, which violates its safe and idempotent nature.POST
is used for a read operation, whereGET
would be appropriate.DELETE
is used for logout, which doesn’t involve a resource deletion — it manipulates session state, which is conceptually different.
✅ Good Example: Correct Mapping of HTTP Methods
GET /users/123 // Retrieve user information
POST /users // Create a new user
PUT /users/123 // Replace user information
PATCH /users/123 // Partially update user info
DELETE /users/123 // Delete a user
These examples use HTTP methods as intended:
GET
is used to retrieve resources without side effects.POST
is for creating new entries.PUT
replaces a resource, whilePATCH
updates part of it.DELETE
is used to remove a resource.
📌 Summary of HTTP Method Semantics
Method | Purpose | Characteristics |
---|---|---|
GET | Retrieve data | Safe, Idempotent |
POST | Create resource | Not idempotent, modifies state |
PUT | Replace resource | Idempotent |
PATCH | Update resource partially | Not necessarily idempotent |
DELETE | Delete resource | Idempotent |
🔑 Key Takeaway
Choosing the right HTTP method is not just a matter of convention — it’s about making your API semantically correct, predictable, and safe to use. When clients rely on HTTP semantics for caching, error handling, or retry logic, misusing methods can break everything.
3.3 Inconsistent URI Structures
A URI (Uniform Resource Identifier) is more than just an address — it’s the foundation of your API’s interface. When URIs follow inconsistent patterns, developers struggle to predict endpoint behavior, documentation becomes harder to maintain, and the overall API becomes frustrating to use.
URI inconsistency is common in projects that lack centralized API governance or have evolved through multiple teams. Let’s look at some real-world examples of inconsistency.
🚫 Bad Example: Inconsistent Naming and Structure
GET /user-list
GET /users/info
POST /create_user
PUT /userUpdate
DELETE /delete-user
This API suffers from several inconsistencies:
- Mixed naming conventions (hyphen, underscore, camelCase)
- Inconsistent use of plural and singular nouns (
/user
vs/users
) - Verbs in the URI instead of using proper HTTP methods
✅ Good Example: Consistent, Resource-Based Design
GET /users
GET /users/123
POST /users
PUT /users/123
DELETE /users/123
In this version, consistency is maintained across:
- Resource naming: all URIs refer to
/users
- HTTP methods: each method conveys the operation (read, create, update, delete)
- ID-based access: specific resources are accessed via URI path parameters
📌 Example of Hierarchical Relationships
Sometimes it’s necessary to represent sub-resources (e.g., posts that belong to a user). In that case, nested URIs can be used — but with care:
GET /users/123/posts
GET /users/123/comments
📊 Summary: URI Naming Best Practices
Practice | Bad Example | Good Example |
---|---|---|
Use plural nouns | /user | /users |
Avoid verbs in URIs | /getUser | /users/{id} |
Express hierarchy clearly | /commentsByUser | /users/{id}/comments |
🔑 Key Takeaway
Consistency is one of the most underrated superpowers of a great API. A predictable, well-structured URI pattern not only improves developer productivity but also enhances the maintainability and scalability of your API over time. Think of URIs as the language of your API — speak it clearly, and speak it the same way every time.
3.4 Ignoring or Misusing HTTP Status Codes
HTTP status codes are a vital part of RESTful API communication. They tell the client what happened — success, failure, partial success, redirection, or server error — in a standardized, machine-readable way. Yet in many APIs, status codes are either misused, oversimplified, or completely ignored.
The most common (and dangerous) pattern? Always returning 200 OK
— even when something goes wrong.
🚫 Bad Example: Always Returning 200 OK
HTTP/1.1 200 OK
{
"status": "error",
"message": "User not found"
}
This is misleading for both humans and machines. The client has no way of knowing — without inspecting the body — that something went wrong. Automated error handling, retries, and analytics all break down.
✅ Good Example: Accurate Use of HTTP Status Codes
HTTP/1.1 404 Not Found
{
"error": {
"code": "USER_NOT_FOUND",
"message": "No user exists with ID 123"
}
}
This version separates transport-level signaling (via the status code) from application-level messaging (in the body). It allows the client to quickly determine that the resource doesn’t exist — and act accordingly.
📊 Summary: Common HTTP Status Codes and Their Meaning
Code | Meaning | When to Use |
---|---|---|
200 OK | Request successful | Generic success, especially for GET or PUT |
201 Created | Resource created | Use after successful POST |
204 No Content | Success with no body | Used after DELETE or silent updates |
400 Bad Request | Client sent invalid request | Missing parameters, invalid syntax, etc. |
401 Unauthorized | Authentication required | Client must log in |
403 Forbidden | Access denied | Client is authenticated but not authorized |
404 Not Found | Resource does not exist | Invalid resource ID, non-existent endpoint |
500 Internal Server Error | Unexpected server error | Unhandled exception, server misconfiguration |
🔑 Key Takeaway
Your API’s status codes are not just metadata — they are part of the API’s contract. When used properly, they give consumers instant clarity, reduce debugging time, and allow tools (like proxies and SDKs) to behave predictably. Don’t just throw 200 OK
at every response — speak the language of HTTP.
3.5 Over-Nesting of Resource URIs
Nesting resources in URIs is a common way to express relationships in RESTful APIs. It makes sense conceptually: a user has posts, a post has comments, and so on. However, when this nesting becomes too deep, it harms usability, flexibility, and maintainability.
The key is moderation. Just because a resource is logically related doesn’t mean it should be deeply embedded in the URI.
🚫 Bad Example: Over-Nested URIs
GET /users/123/posts/456/comments/789/likes/321
This endpoint forces the client to provide the full context chain — user ID, post ID, comment ID — just to retrieve a “like.” In many cases, the like
resource is globally identifiable and does not require this deeply nested path.
✅ Good Example: Flatten Where Appropriate
GET /likes/321
This URI accesses the same resource in a more direct way. If the resource can be uniquely identified without full context, a flat structure is cleaner and easier to use.
✅ When Nesting is Useful
GET /posts/456/comments
POST /posts/456/comments
Nesting is helpful when:
- The sub-resource cannot exist without the parent
- The context improves clarity for both the client and the server
- It’s part of a collection query, not a unique lookup
📊 URI Nesting Guidelines
Nesting Level | Example | Recommended? |
---|---|---|
1 level | /users/123 | ✅ Yes (simple lookup) |
2 levels | /users/123/posts | ✅ Yes (clear hierarchy) |
3+ levels | /users/123/posts/456/comments/789 | ⚠️ Use with caution |
🔑 Key Takeaway
Use URI nesting to clarify relationships — not to enforce rigid paths. When the parent resource is essential to the meaning or identity of the child, nesting helps. But for most lookups, a flat structure provides cleaner access, better caching, and simpler client-side logic.
3.6 Poor Handling of Filtering, Sorting, and Pagination
When designing list or collection endpoints in a RESTful API, filtering, sorting, and pagination are essential for performance, usability, and scalability. Yet many APIs implement these features in a non-standard or inconsistent way — or worse, ignore them altogether.
This often leads to bloated responses, hardcoded logic, and limited control for clients who need to display or interact with large datasets.
🚫 Bad Example: Path-Based Filtering and Pagination
GET /users/age/30
GET /users/sortBy/name/desc
GET /users/page/2/limit/10
These endpoints hard-code filtering, sorting, and pagination logic into the URI path, making them inflexible, verbose, and difficult to combine or extend. This design does not scale well.
✅ Good Example: Use Query Parameters
GET /users?age=30
GET /users?sort=name&order=desc
GET /users?page=2&limit=10
GET /users?age=30&sort=name&order=asc&page=1&limit=20
This approach follows widely accepted RESTful conventions. Query parameters allow the client to dynamically apply filters and sorting logic without modifying the path. They are also easier to document, test, and cache.
📌 Recommended Query Parameters
Type | Parameter | Purpose |
---|---|---|
Filtering | ?status=active | Return only active users |
Sorting | ?sort=name&order=asc | Sort by name in ascending order |
Pagination | ?page=3&limit=25 | Return 25 results from page 3 |
📦 Include Pagination Metadata in the Response
{
"data": [...],
"meta": {
"page": 2,
"limit": 10,
"totalPages": 5,
"totalItems": 50
}
}
Providing pagination metadata helps clients build user-friendly navigation components, display total result counts, and avoid duplicate requests.
🔑 Key Takeaway
Filtering, sorting, and pagination aren’t extras — they’re essential for scalable list APIs. Follow standard query parameter conventions, return useful metadata, and give your clients the tools they need to control how data is displayed. Simplicity and consistency here will save everyone time and frustration.
3.7 Unstructured or Unhelpful Error Responses
Errors are inevitable in any API. But how your API communicates those errors makes all the difference between a developer-friendly experience and a nightmare. Unfortunately, many APIs respond with vague, inconsistent, or completely unstructured error messages — leaving clients guessing what went wrong.
🚫 Bad Example: Vague Error Message
{
"message": "Something went wrong"
}
This tells the client nothing about what happened, where it failed, or how to fix it. Was it a validation error? A permission issue? A missing resource? Clients are left to dig through logs or contact support.
✅ Good Example: Structured Error Response
{
"error": {
"code": "USER_NOT_FOUND",
"message": "No user found with ID 123",
"details": {
"userId": "123"
},
"timestamp": "2025-04-17T10:21:00Z"
}
}
A structured response like this provides clear information that both developers and machines can understand. It supports better debugging, clearer logs, and even user-facing error messages in the client.
📌 Recommended Fields in an Error Object
Field | Purpose |
---|---|
code | A short, unique identifier for the error (e.g., INVALID_PARAMETER ) |
message | A human-readable explanation of what went wrong |
details | Optional contextual data (e.g., which field failed) |
timestamp | When the error occurred (use ISO 8601 format) |
🔐 Security Tip
Be careful not to expose sensitive implementation details in your error responses. For example, instead of saying “Password is incorrect,” a more secure message would be “Invalid username or password.” Avoid leaking internal exceptions or database errors to the client.
🔑 Key Takeaway
A good API error response is not just technically correct — it’s actionable, consistent, and predictable. Structured errors help clients recover gracefully, improve resilience, and reduce support requests. Invest in clear error contracts just as you would in your success responses.
3.8 No Versioning Strategy
APIs are living contracts. Over time, requirements evolve, business logic changes, and improvements are introduced. Without a proper versioning strategy, these changes can break existing clients — causing service disruptions, broken apps, and developer frustration.
Yet many APIs are launched without any versioning at all. Changes are pushed directly to live endpoints, often with unintended consequences.
🚫 Bad Example: No Versioning
GET /users
This endpoint works — until you need to change its response structure, modify field names, or add new parameters. Any change could break clients who depend on the original behavior.
✅ Good Example: URI Versioning
GET /v1/users
GET /v2/users
This approach is simple, transparent, and widely adopted. It makes versioning explicit and allows multiple versions to be supported in parallel. Documentation, client SDKs, and caching all benefit from this clarity.
✅ Alternative: Header-Based Versioning
GET /users
Accept: application/vnd.example.v2+json
This strategy keeps the URI clean and moves versioning into the HTTP headers. It offers flexibility — especially when different versions are needed for the same resource — but may not be supported by all clients or caching layers. It also adds complexity to documentation and testing.
📊 Comparison: URI vs Header Versioning
Aspect | URI Versioning | Header Versioning |
---|---|---|
Visibility | High (easy to see) | Low (hidden in headers) |
Ease of testing | Simple with tools like Postman | Requires header customization |
Client support | Universal | May be limited in some browsers/tools |
Clean URLs | No — version appears in path | Yes — clean, RESTful URL structure |
📦 Bonus Tip: Deprecation Strategy
When introducing new versions, always plan for deprecation:
- Notify clients well in advance
- Log usage of deprecated versions
- Set deprecation headers (e.g.,
Deprecation
,Sunset
) - Offer upgrade guides and change logs
🔑 Key Takeaway
Your API will evolve — and your versioning strategy determines how gracefully that evolution happens. Versioning is not an afterthought — it’s a critical design decision that protects the integrity of your API and the trust of the developers who depend on it.
4. Case Study: Refactoring a Poorly Designed API
Understanding RESTful principles is one thing — applying them to real-world code is another. In this section, we’ll walk through a case study of a fictional company’s user management API, examining what went wrong and how it can be improved using RESTful best practices.
🔍 Scenario: A User API at “Acme Corp”
Acme Corp developed an internal API to manage user accounts. The API was functional but suffered from poor design choices, leading to confusion among developers, brittle integrations, and difficulty extending features.
🚫 Original API (RPC-style design)
GET /getUserInfo?id=123
POST /createUser
POST /updateUser
POST /deleteUser
Issues with this design:
- Verb-based endpoints instead of resource URIs
- Overuse of POST for every operation
- No use of path parameters to identify specific users
- No clear HTTP semantics — clients must guess the intent
✅ Refactored API (RESTful design)
GET /users/123
POST /users
PUT /users/123
DELETE /users/123
Improvements made:
- Consistent, plural resource naming (
/users
) - Proper use of HTTP verbs to signal intent
- URI paths clearly identify individual resources via IDs
- Behavior is intuitive, predictable, and easier to document
📄 Response Example: User Not Found (404)
HTTP/1.1 404 Not Found
{
"error": {
"code": "USER_NOT_FOUND",
"message": "User with ID 123 does not exist."
}
}
📄 Response Example: Create User (201)
HTTP/1.1 201 Created
Location: /users/124
{
"id": 124,
"name": "Jane Doe",
"email": "jane@example.com",
"role": "editor"
}
📊 Before & After Comparison
Aspect | Original API | Refactored RESTful API |
---|---|---|
Endpoint style | Verb-based | Resource-based |
HTTP methods | POST for everything | GET, POST, PUT, DELETE appropriately used |
Resource access | Query parameters | Path parameters |
Developer experience | Confusing and inconsistent | Clear, consistent, and intuitive |
🧠 Lessons Learned
- Verb-based URIs don’t scale well and break RESTful conventions
- Using HTTP semantics improves both developer understanding and tooling compatibility
- Path-based resource identification is more intuitive than query-based access
- Refactoring to REST doesn’t mean rewriting your backend logic — it means rethinking your interface
🔑 Key Takeaway
A well-designed API is not just functional — it’s expressive. It conveys intent, respects standards, and invites collaboration. By refactoring toward RESTful design, even legacy APIs can be transformed into interfaces that developers trust and love to use.
5. RESTful API Best Practices
Designing a RESTful API isn’t just about avoiding mistakes — it’s about establishing clear, consistent patterns that enhance developer experience, improve scalability, and support long-term maintainability. This chapter consolidates essential best practices that every RESTful API should follow.
📘 1. Consistent URI Design
- Use plural nouns for resources:
/users
,/orders
, not/user
- Use path parameters for resource IDs:
/users/123
- Use query parameters for filters, sorting, and pagination
- Never include verbs in URIs — let HTTP methods express actions
📘 2. Proper Use of HTTP Methods
Method | Purpose | Characteristics |
---|---|---|
GET | Read a resource | Safe, idempotent |
POST | Create a resource | Not idempotent |
PUT | Replace a resource | Idempotent |
PATCH | Partially update a resource | May or may not be idempotent |
DELETE | Remove a resource | Idempotent |
📘 3. Use Meaningful Status Codes
200 OK
– Success (GET, PUT)201 Created
– Resource successfully created (POST)204 No Content
– Success with no response body (DELETE)400 Bad Request
– Invalid input401 Unauthorized
,403 Forbidden
– Authentication/Authorization errors404 Not Found
– Resource does not exist500 Internal Server Error
– Server-side error
📘 4. Provide Structured Error Responses
- Use a consistent error format with
code
,message
,details
, andtimestamp
- Include meaningful error codes for programmatic handling
- Avoid exposing sensitive stack traces or internal exception details
📘 5. Implement Versioning Early
- Use
/v1/
,/v2/
in the URI or media type versioning via HTTP headers - Never change API behavior without version control
- Document deprecated versions and set a sunset policy
📘 6. Support Pagination, Filtering, and Sorting
- Standard parameters:
?page
,limit
,sort
,order
,filter
- Return metadata like
totalItems
,totalPages
, etc. - Allow compound filters and multiple sorting criteria where possible
📘 7. Use OpenAPI (Swagger) for Documentation
- Document every endpoint, parameter, and response
- Provide examples for requests and responses
- Keep the spec updated as the API evolves
📘 8. Secure Your API
- Use HTTPS for all traffic
- Implement token-based authentication (e.g., JWT, OAuth2)
- Enforce role-based access control where needed
- Rate-limit requests to prevent abuse
🔑 Final Thought
A great RESTful API is not just functional — it’s thoughtful. It anticipates the needs of the developer, respects HTTP standards, and grows gracefully as the application evolves. Following these best practices helps you deliver an interface that is clean, reliable, and delightful to use.
6. Conclusion: An API Is a Contract
A RESTful API is more than just a tool — it’s a contract. It defines how clients and servers interact, what they can expect, and how they should behave. A well-designed API establishes trust. A poorly designed one breeds confusion and frustration.
Throughout this guide, we’ve explored the most common mistakes developers make when building APIs: inconsistent URIs, misused HTTP methods, lack of versioning, vague error responses, and more. We’ve also learned how to fix those issues with clear, predictable, and scalable patterns that align with RESTful principles.
REST isn’t just a style — it’s a philosophy. It encourages you to think in terms of resources, state transitions, and clarity of intent. When your API is truly RESTful, developers shouldn’t need to read pages of documentation just to make a request. The interface should speak for itself.
In a world increasingly driven by integration — across mobile apps, microservices, third-party platforms, and beyond — your API is often the first and most important interface you expose. It’s a handshake, a promise, and a guide all in one.
🔑 Final Message
Good APIs don’t just work — they teach. They’re discoverable, consistent, and respectful of the developer’s time. They’re not a technical afterthought; they’re a product. And like any good product, they should delight their users, not frustrate them.
Design your API like you would design a user interface: with empathy, discipline, and a long-term vision. Because at the end of the day, a great API isn’t just about code — it’s about communication.
Title: 8 Common Mistakes in RESTful API Design — And How to Fix Them with Real Examples Slug (Permalink): restful-api-mistakes-and-best-practices Meta Description: Learn how to identify and fix common RESTful API design mistakes with real-world examples and best practices. Labels/Tags: RESTful API, API Design, Web Development, Backend Architecture, API Best Practices, Developer Experience