Back to HTTP Methods
Q5Question 5 of 5

What should a GET call return if no entity is found (404 vs 200 with an empty array vs 204)

Key Concepts
  • A missing single resource returns 404 Not Found because the identified resource is genuinely absent.
  • A collection with no matching items returns 200 OK with an empty array because zero results is a valid, successful answer.
  • 204 No Content is for intentionally no body, like after a DELETE, and is almost never correct for a GET that found nothing.
  • If the parent resource in the path does not exist, return 404 because the parent path is genuinely invalid.
  • Consistency across the API matters more than any single rule: pick a convention, document it, and apply it everywhere.
  • Returning 200 with an empty body for a missing resource confuses clients, while returning 404 for an empty collection forces unnecessary error handling.

Definition

A missing single resource gets 404, a collection with no matches gets 200 with an empty array, and 204 is for intentionally no body like after a DELETE, not for not-found.
  • Single resource missing – return 404 Not Found because the identified resource is genuinely absent.
  • Empty collection – return 200 OK with an empty array [] because the collection exists and zero items is a valid, successful answer.
  • 204 No Content – appropriate when there is deliberately no body to return, such as after a successful DELETE; it is not the right choice for a GET that found nothing.
  • Parent missing – if the parent in the path does not exist, like /accounts/SAV9999/transactions where SAV9999 is invalid, return 404 because the parent path is genuinely absent.
  • Consistency – pick a rule and apply it across the entire API so client handling is simple and predictable.

Imagine asking National Bank of India two different questions. First, "show me account SAV9999": it does not exist, so the clerk says "account not found" – that is a 404. Second, "list all transactions by Rajesh over one crore this month": there happen to be none, but the question is valid and the answer is an empty list, so the clerk says "here is your list, it is empty" – that is a 200 with an empty array. The second is not an error; zero results is a perfectly good answer.

Understanding the Concepts

What is the core distinction?

The key distinction is single resource versus collection. When the URL identifies one specific resource, like GET /accounts/SAV9999, and that resource does not exist, the honest answer is 404 Not Found. When the URL identifies a collection, like GET /accounts/SAV2001/transactions?minAmount=10000000, and nothing matches, the collection itself exists and zero results is a valid success.

JAVA
// Single resource: 404 when absent.
// GET /api/v1/accounts/SAV9999  → 404 Not Found

// Collection with no matches: 200 with empty array.
// GET /api/v1/accounts/SAV2001/transactions?minAmount=10000000  → 200 OK + []

When should you return 404?

Return 404 when the client asks for a specific resource by ID and that resource does not exist. Returning 200 with an empty body would be misleading because the client cannot tell the difference between found-but-empty and not-found.

JAVA
package com.bank.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/v1/accounts")
public class AccountController {

    @GetMapping("/{id}")
    public ResponseEntity<AccountResponse> get(@PathVariable String id) {
        return accountService.find(id)
                .map(ResponseEntity::ok)                    // 200 if found
                .orElse(ResponseEntity.notFound().build()); // 404 if missing
    }
}

When should you return 200 with an empty array?

Return 200 with an empty array when the client queries a collection and no items match. The collection endpoint exists, the query is valid, and zero items is the correct answer. Returning 404 here would be wrong because it suggests the endpoint or parent resource does not exist.

JAVA
@GetMapping("/{accountId}/transactions")
public ResponseEntity<List<TransactionResponse>> listTransactions(
        @PathVariable String accountId,
        @RequestParam(required = false) java.math.BigDecimal minAmount) {
    List<TransactionResponse> txns = transactionService.find(accountId, minAmount);
    return ResponseEntity.ok(txns); // 200 even if txns is empty []
}

When should you return 204?

204 No Content means the request succeeded and there is intentionally no body. It is the right choice after a successful DELETE or sometimes a PUT where you choose not to echo the resource. For a GET, 204 is almost never correct because GET is a request for a representation.

JAVA
// 204 after a successful DELETE: correct.
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable String id) {
    beneficiaryService.delete(id);
    return ResponseEntity.noContent().build(); // 204 No Content
}

// 204 for a GET that found nothing: incorrect.
// Do not use 204 for GET – use 404 or 200 with empty array instead.

What happens when the parent resource does not exist?

If the parent in the path does not exist, like GET /accounts/SAV9999/transactions where account SAV9999 itself does not exist, the cleaner approach is 404 because the parent path is genuinely invalid. Return 200 with an empty array only when the parent exists but has no children.

JAVA
@GetMapping("/{accountId}/transactions")
public ResponseEntity<List<TransactionResponse>> list(@PathVariable String accountId) {
    // First check: does the parent account exist?
    if (!accountService.exists(accountId)) {
        return ResponseEntity.notFound().build(); // 404: parent does not exist
    }
    List<TransactionResponse> txns = transactionService.findByAccount(accountId);
    return ResponseEntity.ok(txns); // 200 with empty array if no transactions
}

How do you implement this consistently across the API?

Consistency matters more than any single philosophical stance. Pick a rule: single missing is 404, collection empty is 200 with empty array. Apply it everywhere, document it, and make client code simple. Clients handle empty arrays naturally by looping zero times, whereas a surprise 404 on an empty collection forces special-case error handling.

JAVA
// Consistent pattern across all endpoints:
// GET /accounts/{id}               → 200 or 404 (single resource)
// GET /accounts/{id}/transactions   → 200 with [] or 404 if parent missing
// GET /beneficiaries                → 200 with [] (collection, always exists)
// DELETE /beneficiaries/{id}        → 204 (no body)

What are common mistakes?

A common mistake is returning 200 with an empty body for a missing single resource, which confuses clients. Another is returning 404 for an empty collection, which makes clients handle a normal case as an error. A third is using 204 for GET responses.

JAVA
// Wrong: 200 with empty body for missing single resource.
@GetMapping("/{id}")
public ResponseEntity<AccountResponse> get(@PathVariable String id) {
    AccountResponse account = accountService.find(id).orElse(null);
    return ResponseEntity.ok(account); // 200 with null body – confusing!
}

// Correct: 404 for missing single resource.
@GetMapping("/{id}")
public ResponseEntity<AccountResponse> get(@PathVariable String id) {
    return accountService.find(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build()); // Clear 404
}

What should a senior engineer know?

A senior engineer knows that the choice between 404 and 200 affects client code quality. An empty array loops zero times naturally, while a 404 requires branching into error handling. They document the API's convention clearly and enforce it with integration tests. They also know that for security-sensitive resources, returning 404 instead of 403 can be a deliberate choice to avoid leaking resource existence.

Visual Overview

DIAGRAM
┌──────────────────────────────────────────────────────┐
│           GET Response Decision Tree                  │
├──────────────────────────────────────────────────────┤
│                                                      │
│  GET request received                                │
│       │                                              │
│       ▼                                              │
│  Is this a single resource or a collection?          │
│       │                         │                    │
│    Single                    Collection              │
│    /accounts/SAV9999         /accounts/SAV2001/txns  │
│       │                         │                    │
│       ▼                         ▼                    │
│  Does the resource exist?   Does the parent exist?   │
│    │           │              │           │          │
│   Yes         No            Yes         No           │
│    │           │              │           │          │
│    ▼           ▼              ▼           ▼          │
│  200 OK      404 Not       Any items?   404 Not     │
│  + body      Found           │          Found       │
│                          │       │                   │
│                         Yes     No                   │
│                          │       │                   │
│                          ▼       ▼                   │
│                        200 OK  200 OK                │
│                        + data  + []                  │
│                                                      │
│  After DELETE: 204 No Content (no body)              │
└──────────────────────────────────────────────────────┘

Key Takeaway

The correct status for a GET that finds nothing depends on whether the client asked for a single resource or a collection. When the URL identifies one specific resource, like account SAV9999, and it does not exist, the right answer is 404 Not Found. When the URL identifies a collection, like a filtered list of transactions, and nothing matches, the right answer is 200 OK with an empty array, because zero results is a valid and successful answer to a valid query.

The reason for being strict about this comes from a real bug at National Bank of India. The old backend returned 200 with an empty body when a single account was missing, so Rajesh's app showed a blank screen with a zero balance and he panicked, thinking his money was gone. The fix was to return 404 for a missing single resource so the app could show a clear "account not found" message. On the other side, the old backend returned 404 when a transaction filter matched nothing, so the app popped up an error even though nothing was wrong. The fix there was 200 with an empty array so the app simply showed "no large transactions this month."

204 No Content is a different thing entirely. It means the request succeeded and there is intentionally no body, which is the right choice after a successful DELETE. It is almost never correct for a GET that found nothing, because a GET is a request for a representation and returning no content blurs the meaning.

The principle applied across the whole API is consistency. Pick the rule: missing single resource is 404, empty collection is 200 with an empty array. Document it. Enforce it. This keeps client code simple because an empty array loops zero times, whereas a surprise 404 on an empty collection forces awkward error handling that is a frequent source of bugs.

Remember one sentence: a missing single resource is 404, an empty collection is 200 with an empty array, and 204 is for intentionally no body after a DELETE.

---

Share
Use ← → arrow keys to navigate