A Practical Guide to Designing RESTful APIs This article provides a practical guide to designing RESTful APIs, emphasizing a resource-oriented approach where endpoints represent nouns and HTTP verbs describe actions, rather than using action-based URLs. It covers key design principles such as proper endpoint structuring, shallow nesting for related resources, and the correct use of HTTP status codes (2xx for success, 4xx for client errors, 5xx for server errors) with informative error responses. The guide includes real code examples in Python using Flask to demonstrate these concepts in practice. Designing RESTful APIs is one of those skills that separates developers who build systems that last from those who end up rewriting everything six months later. A well-designed RESTful API https://journals.telkomuniversity.ac.id/logic/article/download/7530/2483 is predictable, consistent, and easy for other developers to consume without reading a wall of documentation. Whether you are building a public-facing API or an internal service, getting the fundamentals right from the start saves enormous headaches down the line. This guide walks through the practical decisions you will face — from structuring your endpoints to handling errors gracefully — with real code examples to make things concrete. Start With Resources, Not Actions The single most important mental shift when designing a RESTful API is thinking in terms of resources rather than actions. Many developers who come from an RPC or SOAP background tend to design URLs that read like function calls. That is the wrong instinct here. A resource is a noun — a thing your API exposes. An endpoint should represent that thing, and HTTP verbs GET , POST , PUT , PATCH , DELETE should describe what you are doing to it. This distinction keeps your API surface predictable for anyone who consumes it. Consider a user management system. The resource-oriented approach looks like this: GET /users → list all users POST /users → create a new user GET /users/{id} → get a specific user PUT /users/{id} → replace a user entirely PATCH /users/{id} → partially update a user DELETE /users/{id} → delete a user Compare that to the action-based antipattern: /getUser , /createUser , /deleteUser . These work, but they fight against the grain of HTTP and make the API harder to reason about at scale. Handling Nested Resources When one resource belongs to another, nesting reflects that relationship in the URL. An order that belongs to a user might live at /users/{userId}/orders . Keep nesting shallow — no more than two levels deep is a good rule of thumb. Deeply nested URLs become unwieldy and usually signal that you should reconsider your resource model. Use HTTP Status Codes Correctly One of the most common mistakes in API design is returning 200 OK for everything and burying the actual outcome in the response body. HTTP status codes exist precisely to communicate the result of a request at the protocol level, and clients — both human developers and automated systems — rely on them heavily. The codes you will use most often fall into a few categories. 2xx codes mean success: 200 for a general success, 201 when a resource was created, 204 when a request succeeded but there is nothing to return common for DELETE . 4xx codes indicate the client did something wrong: 400 for a malformed request, 401 when authentication is missing, 403 when the user is authenticated but lacks permission, 404 when the resource does not exist, 422 when the input is syntactically valid but semantically wrong. 5xx codes are for server-side failures. Here is an example in Python using Flask that demonstrates this properly: python from flask import Flask, jsonify, request app = Flask name users = {1: {"name": "Alice", "email": "alice@example.com"}} @app.route "/users/