Handling Zero vs Null in API Responses: The != null Pattern

📖 2 minutes read

A common bug in Laravel APIs: numeric fields that can be zero display as empty or dash in the frontend because of JavaScript’s falsy value handling. The fix is simple but often overlooked.

The Problem

You have an API that returns configuration with numeric values:

// Backend returns: {"discount_rate": 0}

Frontend code using truthy checks:

// ❌ Displays "—" for zero
{{ config.discount_rate ? config.discount_rate + '%' : '—' }}
// Result: "—" (wrong!)

Why It Fails

In JavaScript, 0 is falsy, so the ternary condition fails and shows the fallback. But 0 might be a perfectly valid value (like “0% discount”).

The Fix

// ✅ Explicit null check
{{ config.discount_rate != null ? config.discount_rate + '%' : '—' }}
// Result: "0%" (correct!)

Backend Considerations

Make sure your Laravel API distinguishes between null (not set) and zero (explicitly set to 0):

// ❌ Bad: Converts 0 to null
public function index()
{
    return [
        'discount_rate' => $model->discount_rate ?: null
    ];
}

// ✅ Good: Preserves zero, only null when actually null
public function index()
{
    return [
        'discount_rate' => $model->discount_rate
    ];
}

Common Scenarios

  • Percentages: 0% is valid (no discount/markup)
  • Counts: 0 items is different from unknown
  • Ratings: 0 stars might be valid vs unrated
  • Prices: $0.00 (free) vs null (price not set)

Pattern for Multiple Fields

// Vue/React pattern
const formatValue = (value) => {
    return value != null ? `${value}%` : '—';
};

<template>
    <div>Base Rate: {{ formatValue(config.base_rate_markup) }}</div>
    <div>Extra Rate: {{ formatValue(config.extra_rate_markup) }}</div>
</template>

Testing Strategy

Always test these edge cases:

  1. Field is null (not set) → shows fallback
  2. Field is 0 → shows “0” or “0%”
  3. Field is positive number → shows number
  4. Field is negative number (if valid) → shows number

Database Schema Consideration

In migrations, be explicit about nullability:

// If 0 and null have different meanings
$table->decimal('discount_rate', 5, 2)->nullable();
// null = not configured, 0 = explicitly set to zero

// If 0 is the default ("no discount")
$table->decimal('discount_rate', 5, 2)->default(0);
// Always has a value, never null

The Rule of Thumb

  • Use value != null when zero is meaningful
  • Use value || default when zero should fallback (rare for numbers)
  • Document the distinction in your API responses

This small change prevents countless “the UI shows dash instead of zero” bug reports.

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *