HeoLab
ToolsBlogAboutContact
HeoLab

Free developer tools with AI enhancement. Built for developers who ship.

Tools

  • JSON Formatter
  • JWT Decoder
  • Base64 Encoder
  • Timestamp Converter
  • Regex Tester
  • All Tools →

Resources

  • Blog
  • What is JSON?
  • JWT Deep Dive
  • Base64 Explained

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 HeoLab. All rights reserved.

Tools work in your browser. Zero data retention.

HomeBlogREST API Design Best Practices in 2025
Table of Contents▾
  • Resource Naming
  • HTTP Methods
  • Status Codes — Use Them Correctly
  • Error Response Format
  • Versioning
  • URL path (most common, easiest to cache)
  • Header (clean URLs, harder to test)
  • Query parameter (avoid — versioning should be stable)
  • Pagination
  • Offset pagination (simple, works everywhere)
  • Cursor pagination (better for real-time data)
  • Filtering and Sorting
  • Filtering
  • Sorting
  • Field selection (sparse fieldsets)
  • Headers Every API Should Return
api#rest#api#backend

REST API Design Best Practices in 2025

How to design REST APIs that developers love — resource naming, HTTP methods, status codes, versioning, pagination, and error handling patterns.

Trong Ngo
February 23, 2026
4 min read

A well-designed REST API is a joy to work with. A poorly designed one generates endless support tickets. These are the patterns that separate production-grade APIs from amateur ones.

Resource Naming

Resources are nouns, not verbs. HTTP methods are the verbs.

✓ Good                          ✗ Bad
GET    /users                   GET /getUsers
POST   /users                   POST /createUser
GET    /users/123               GET /getUserById?id=123
PUT    /users/123               POST /updateUser/123
DELETE /users/123               DELETE /deleteUser?id=123
GET    /users/123/orders         GET /getUserOrders/123
POST   /users/123/orders         POST /createOrderForUser

Rules:

  • Use plural nouns: /users, /orders, /products
  • Use kebab-case for multi-word: /order-items, not /orderItems
  • Nest resources only 2 levels deep maximum
  • Use query params for filtering/sorting, not path params

HTTP Methods

MethodUseIdempotentBody
GETFetch resource(s)YesNo
POSTCreate new resourceNoYes
PUTReplace entire resourceYesYes
PATCHUpdate partial resourceNoYes
DELETERemove resourceYesNo

Idempotent means calling it multiple times has the same result as calling it once.

Status Codes — Use Them Correctly

2xx — Success
  200 OK            — GET, PUT, PATCH success
  201 Created       — POST success (include Location header)
  204 No Content    — DELETE success, or PATCH with no body

3xx — Redirection
  301 Moved Permanently  — resource moved, update your links
  304 Not Modified       — for caching (ETag/If-None-Match)

4xx — Client Errors
  400 Bad Request    — invalid JSON, missing required field
  401 Unauthorized   — missing or invalid auth token
  403 Forbidden      — authenticated but not allowed
  404 Not Found      — resource doesn't exist
  409 Conflict       — duplicate resource, version conflict
  422 Unprocessable  — valid JSON but fails validation
  429 Too Many Reqs  — rate limit exceeded

5xx — Server Errors
  500 Internal Error — unhandled exception
  502 Bad Gateway    — upstream service failed
  503 Unavailable    — server overloaded or down for maintenance

Error Response Format

Be consistent. Every error response should have the same structure:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      { "field": "email", "message": "Invalid email format" },
      { "field": "age", "message": "Must be at least 18" }
    ],
    "requestId": "req_01HXYZ...",
    "timestamp": "2025-01-15T10:30:00Z"
  }
}

Never return { success: false, data: null } without error context.

Versioning

Three common approaches:

# URL path (most common, easiest to cache)
GET /api/v1/users
GET /api/v2/users

# Header (clean URLs, harder to test)
GET /api/users
Accept: application/vnd.myapi.v2+json

# Query parameter (avoid — versioning should be stable)
GET /api/users?version=2

Recommendation: URL path versioning for public APIs. Only version when introducing breaking changes.

Pagination

Never return unbounded lists. Three patterns:

# Offset pagination (simple, works everywhere)
GET /users?page=2&limit=20

Response:
{
  "data": [...],
  "pagination": {
    "page": 2, "limit": 20,
    "total": 340, "pages": 17
  }
}

# Cursor pagination (better for real-time data)
GET /posts?after=01ARZ3NDEK&limit=20

Response:
{
  "data": [...],
  "nextCursor": "01ARZXXX",
  "hasMore": true
}

Cursor pagination is better for feeds and frequently updated data — offset pagination skips or duplicates items when records are added/removed mid-pagination.

Filtering and Sorting

# Filtering
GET /users?status=active&role=admin
GET /orders?created_after=2025-01-01&created_before=2025-02-01

# Sorting
GET /users?sort=created_at&order=desc
GET /users?sort=-created_at        # minus prefix for desc (OpenAPI convention)

# Field selection (sparse fieldsets)
GET /users?fields=id,name,email    # return only these fields

Headers Every API Should Return

Content-Type: application/json; charset=utf-8
X-Request-Id: req_01HXYZ...          # for distributed tracing
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1705315200
Cache-Control: no-store              # for auth endpoints

Test your API endpoints with the HTTP Status Codes reference and convert curl examples to fetch/axios with the cURL Converter tool.

Try These Tools

HTTP Status Codes

Complete reference for all HTTP status codes with descriptions, use cases, and RFC links.

cURL Converter

Convert curl commands to fetch, axios, HTTPie, and other HTTP client formats.

JSON Formatter & Validator

Format, validate, and beautify JSON data instantly. Detect errors with precise line numbers.

Related Articles

YAML vs JSON: When to Use Each and How to Convert Between Them

3 min read

Docker Commands Cheatsheet for Developers

4 min read

CSS Gradients: The Complete Guide (Linear, Radial, Conic)

3 min read

Back to Blog

Table of Contents

  • Resource Naming
  • HTTP Methods
  • Status Codes — Use Them Correctly
  • Error Response Format
  • Versioning
  • URL path (most common, easiest to cache)
  • Header (clean URLs, harder to test)
  • Query parameter (avoid — versioning should be stable)
  • Pagination
  • Offset pagination (simple, works everywhere)
  • Cursor pagination (better for real-time data)
  • Filtering and Sorting
  • Filtering
  • Sorting
  • Field selection (sparse fieldsets)
  • Headers Every API Should Return

Related Articles

YAML vs JSON: When to Use Each and How to Convert Between Them

3 min read

Docker Commands Cheatsheet for Developers

4 min read

CSS Gradients: The Complete Guide (Linear, Radial, Conic)

3 min read