Backend Development 13 min read

Best Practices for Designing HTTP APIs: Status Codes, JSON Payloads, Resource Naming, and Error Handling

This guide outlines comprehensive backend API design recommendations, covering appropriate HTTP status codes, JSON request bodies, unique resource identifiers, timestamp formats, consistent URL structures, nested relationships, error message schemas, caching, pagination, versioning, security, and clear documentation with executable examples.

Architecture Digest
Architecture Digest
Architecture Digest
Best Practices for Designing HTTP APIs: Status Codes, JSON Payloads, Resource Naming, and Error Handling

Return appropriate status codes

Each response should use a suitable HTTP status code. Successful responses use:

200 : GET succeeded, or DELETE/PATCH synchronous completion.

201 : POST synchronous completion.

202 : POST, DELETE, or PATCH asynchronous request accepted.

206 : Partial GET response (example shown).

For client errors and server exceptions, refer to the full HTTP response code specification.

Provide all available resources

When the response code is 200 or 201, return the full set of visible resources, including attributes for PUT/PATCH/DELETE requests. Example:

$ curl -X DELETE \
  https://service.com/apps/1f9b/domains/0fd4

HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
...
{
  "created_at": "2012-01-01T12:00:00Z",
  "hostname": "subdomain.example.com",
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "updated_at": "2012-01-01T12:00:00Z"
}

If the status code is 202, do not return the full resource set. Example:

$ curl -X DELETE \
  https://service.com/apps/1f9b/dynos/05bd

HTTP/1.1 202 Accepted
Content-Type: application/json;charset=utf-8
...
{}

Use JSON data in request bodies

PUT, PATCH, and POST request bodies should be JSON, not form‑encoded. Example:

$ curl -X POST https://service.com/apps \
    -H "Content-Type: application/json" \
    -d '{"name": "demoapp"}'

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "name": "demoapp",
  "owner": {
    "email": "[email protected]",
    "id": "01234567-89ab-cdef-0123-456789abcdef"
  },
  ...
}

Provide a unique identifier for resources

Assign each resource an id attribute, preferably a globally unique UUID in the 8‑4‑4‑4‑12 format, e.g., "01234567-89ab-cdef-0123-456789abcdef".

Provide standard timestamps

Include created_at and updated_at fields using ISO‑8601 UTC format, e.g., "2012-01-01T12:00:00Z". Omit if not applicable.

Use ISO‑8601 international time format

All returned time values must be in UTC ISO‑8601 format, such as:

"finished_at": "2012-01-01T12:00:00Z"

Use unified resource paths

Resource naming

Use plural nouns for resource names to keep URLs consistent.

Action naming

When a special action is required, use an actions prefix, e.g., /resources/:resource/actions/:action . Example:

/runs/{run_id}/actions/stop

Use lowercase letters for paths and attributes

Paths should be lowercase with hyphens as separators, e.g., service-api.com/users . Attribute names use lowercase with underscores, e.g., service_class .

Nested foreign‑key relationships

Embed related objects instead of exposing only foreign‑key IDs. Example of nested owner object:

{
  "name": "service-production",
  "owner": {
    "id": "5d8201b0...",
    "name": "Alice",
    "email": "[email protected]"
  },
  ...
}

Support convenient indirect references without ID

Allow resources to be accessed by both name and ID, e.g.:

$ curl https://service.com/apps/{app_id_or_name}
$ curl https://service.com/apps/97addcf0-c182
$ curl https://service.com/apps/www-prod

Build error messages

Return structured error objects containing a machine‑readable id , a human‑readable message , and optionally a url for more information. Example:

HTTP/1.1 429 Too Many Requests

{
  "id": "rate_limit",
  "message": "Account reached its API rate limit.",
  "url": "https://docs.service.com/rate-limits"
}

Support ETag caching

Include an ETag header in all responses and honor If-None-Match in subsequent requests.

Use an ID to track each request

Include a Request-Id header (a UUID) in every response to aid debugging and tracing.

Range pagination

For large result sets, paginate using the Content-Range header.

Show rate‑limit status

Return the remaining request tokens via the RateLimit-Remaining header.

Specify acceptable header version

Clients must explicitly set the API version using the Accept header, e.g., Accept: application/vnd.heroku+json; version=3 .

Reduce path nesting

Limit deep nesting by exposing top‑level resources and using shallow paths, e.g., /orgs/{org_id} , /apps/{app_id} , /dynos/{dyno_id} .

Provide a machine‑readable JSON schema

Use tools like prmd to generate and verify a JSON schema with prmd verify .

Provide human‑readable documentation

Generate Markdown documentation from the schema using prmd doc for developers.

Provide executable examples

Include ready‑to‑run command‑line examples so users can copy‑paste directly, e.g.:

$ export TOKEN=... # acquire from dashboard
$ curl -is https://[email protected]/users

Describe stability

Document the API's stability level (prototype, development, production) and follow the Heroku API compatibility policy for versioning.

Require secure transport

All API access must be over HTTPS.

Use friendly JSON output

Print pretty‑printed JSON with line breaks for readability, e.g.:

{
  "beta": false,
  "email": "[email protected]",
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "last_login": "2012-01-01T12:00:00Z",
  "created_at": "2012-01-01T12:00:00Z",
  "updated_at": "2012-01-01T12:00:00Z"
}
backendJSONhttpAPI designStatus CodesWeb ServicesREST
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.