Skip to content

Conversation

@paco-valdez
Copy link
Member

Check List

  • Tests have been run in packages where changes have been made if available
  • Linter has been run for changed code
  • Tests for the changes have been added if not covered yet
  • Docs have been added / updated if required

Summary

Adds title and shortTitle metadata to GraphQL API responses, enabling clients to display human-readable labels without requiring separate /v1/meta REST API calls.

Motivation

Currently, the GraphQL API only returns technical field names (e.g., Orders.count, Users.city) without their human-readable titles. Clients building dynamic UIs need to make additional REST API calls to /v1/meta to fetch this metadata, requiring:

  • Dual API integration (REST + GraphQL)
  • Manual correlation between data and metadata
  • Additional network requests

This change brings the GraphQL API to feature parity with the REST API by including title information directly in query responses.

Changes

Schema Changes

Added three new GraphQL types:

type FloatWithTitle { value: Float title: String shortTitle: String } type StringWithTitle { value: String title: String shortTitle: String } type TimeDimension { value: DateTime! second: DateTime!  # ... other granularities title: String # NEW shortTitle: String # NEW }

Implementation

Modified Files:

  • packages/cubejs-api-gateway/src/graphql.ts - Core implementation
  • packages/cubejs-api-gateway/test/graphql.test.ts - Test coverage

Key Changes:

  1. Created FloatWithTitle and StringWithTitle object types (lines 96-112)
  2. Updated mapType() to return wrapper types for output fields while preserving input types (lines 149-160)
  3. Enhanced resolver to populate title information from existing annotation data (lines 699-744)
  4. Added title and shortTitle fields to TimeDimension type (lines 144-145)
  5. Added comprehensive test case for title functionality (lines 266-380)

Response Format Changes

Before

 { "data": { "cube": [{ "orders": { "count": 150, "status": "completed", "createdAt": { "day": "2024-01-15T00:00:00.000Z" } } }] } }

After

 { "data": { "cube": [{ "orders": { "count": { "value": 150, "title": "Orders Count", "shortTitle": "Count" }, "status": { "value": "completed", "title": "Orders Status", "shortTitle": "Status" }, "createdAt": { "day": "2024-01-15T00:00:00.000Z", "title": "Orders Created At", "shortTitle": "Created At" } } }] } }

Example Query

 query { cube { orders { count status createdAt { day } } } }

Response now includes value, title, and shortTitle for each field, enabling self-documenting UIs.

Benefits

  1. Single API Integration - No need for separate /v1/meta calls
  2. Better Developer Experience - All data and metadata in one request
  3. Improved Performance - Fewer network round-trips
  4. Self-Documenting UIs - Build dynamic interfaces with proper labels
  5. Feature Parity - GraphQL API now matches REST API capabilities

Testing

Added test case should return titles with scalar values that verifies:

  • Measures return with title information
  • Dimensions return with title information
  • Time dimensions include title fields
  • Title data matches metaConfig definitions

Run tests:

cd packages/cubejs-api-gateway
yarn test graphql.test.ts --testNamePattern="should return titles"

Breaking Changes

⚠️ This is a breaking change - Response structure has changed for all fields.

Migration Guide

Clients will need to update their response handling:

Before:
const count = response.data.cube[0].orders.count;
// count = 150

After:
const count = response.data.cube[0].orders.count.value;
const title = response.data.cube[0].orders.count.title;
// count = 150
// title = "Orders Count"

@paco-valdez paco-valdez requested a review from a team as a code owner December 18, 2025 19:18
@github-actions github-actions bot added the javascript Pull requests that update Javascript code label Dec 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

javascript Pull requests that update Javascript code

1 participant