Case Study

← Back to selected work

Dashboard Data Contracts

Reducing duplicated frontend parsing by aligning dashboard APIs around stable, chart-ready response shapes.

Summary

Role

Frontend architecture, API contract collaboration, dashboard data modeling

Scope

Usage analytics, platform-wide metrics, billing-related visibility, chart widgets, filters, loading states

Stack

React, TypeScript, REST APIs, dashboard UI, charting components

Focus

Data contracts, derived state, reusable widgets, maintainability

Overview

My role

Standardized dashboard API response shapes so chart widgets could reuse rendering logic instead of carrying page-specific parsing for every analytics view.

Context

The platform included multiple analytics and operational dashboard views for usage, billing-related visibility, platform-wide metrics, and infrastructure activity. These views needed charts, filters, time ranges, loading states, empty states, and consistent data presentation.

As these dashboard surfaces grew, the frontend needed a more reliable way to consume chart data across multiple pages and widgets.

Problem

The issue was not the chart library itself. The harder problem was inconsistent API response shapes.

Some endpoints returned object maps like { label: value }. Others returned row-based data like { date, value }.

This meant similar charts often needed different frontend parsing logic. Over time, that created several problems:

  • chart components became harder to reuse
  • each page had its own transformation logic
  • loading, empty, and error states became less consistent
  • frontend and backend expectations were not always explicit
  • adding a new dashboard view required repeated parsing decisions
  • small backend shape changes could break page-specific chart logic

Ownership

I pushed for clearer API contracts between frontend and backend, especially for chart-ready and dashboard-ready data.

I worked with backend engineers to define response shapes that better matched how the frontend actually consumed the data. My goal was to reduce one-off parsing inside individual pages and make dashboard widgets easier to reuse, test, and extend.

Before / After Data Contract

Representative schema Dashboard rendering contract

Before: widget-specific parsing

// Simplified examples
{ label: value }

{ date, value }

{ name, count }

Similar dashboard widgets had to understand different response shapes.

After: chart-friendly shape

// Representative schema
{
  categories: ["api", "gpu", "storage"],
  series: [
    { date: "2026-01-01", category: "api", value: 120 },
    { date: "2026-01-01", category: "gpu", value: 40 }
  ]
}

Widgets render from a stable categories + series contract.

API responseRepresentative shape
Boundary layerOne normalization path
Dashboard widgetsReusable render model

Key Decisions

Separate backend storage shape from UI-ready chart shape

Avoid making every chart understand backend-specific response details. Instead, define a stable contract that is closer to what the UI needs.

Standardize around categories and series

Use a consistent structure for categories, dates, and values so widgets can share rendering and transformation logic.

Keep transformation logic close to the data boundary

Normalize data once near the API layer instead of spreading map/filter/reduce logic across individual chart components.

Keep filter state and applied query state explicit

Separate draft filter input from the applied query that drives fetching, cache keys, and rendering.

Normalize loading, empty, and error states

Dashboard widgets should handle these states consistently instead of each page inventing its own behavior.

Design for future dashboard growth

Prefer contracts that support additional metrics, time ranges, and categories without rewriting every widget.

Impact

The standardized contracts reduced duplicated parsing paths and made dashboard work easier to scale.

  • Simplified chart data consumption across analytics and platform metrics views.
  • Reduced frontend transformation logic inside individual dashboard components.
  • Made chart widgets more reusable and predictable.
  • Improved frontend/backend alignment around response expectations.
  • Reduced the risk of small API shape differences creating page-specific bugs.
  • Helped future analytics features move faster with fewer one-off parsing decisions.

Trade-offs

  • A UI-ready contract can require more backend coordination, but it prevents repeated frontend parsing.
  • Generic chart schemas improve reuse, but they should not hide important product-specific meaning.
  • Frontend transformation is fine for small isolated views, but shared dashboards benefit from stronger contracts.
  • A consistent schema is most valuable when multiple charts share similar dimensions such as time, category, and value.

Closing

For dashboard-heavy products, the hard part is often not the chart library. It is the data contract behind the chart.