Skip to content

Feature Request: Introduce Schema Contexts (Views) #85

@sergiobayona

Description

@sergiobayona

Description

Allow models to define multiple schema variants for different contexts, similar to serializer views or API versioning.

Current State

A model has exactly one schema definition defined by the define_schema block:

class User
  include EasyTalk::Model
  
  define_schema do
    property :id, Integer
    property :name, String
    property :email, String
    property :password_hash, String
    property :admin_notes, String
  end
end

User.json_schema  # Returns the single schema

Problem

In real-world applications, the same internal model often needs different representations for different contexts:

  • Public vs Admin views: Hide sensitive fields from public API
  • Create vs Update payloads: id required for update, forbidden for create
  • API versioning: v1 returns full_name, v2 returns first_name + last_name
  • Input vs Output: Different validation rules for receiving vs sending data

Currently, users must create separate model classes for each context, leading to duplication.

Proposed Solution

Allow define_schema to accept a context name:

class User
  include EasyTalk::Model
  
  # Default schema (backward compatible)
  define_schema do
    property :id, Integer
    property :name, String
    property :email, String
  end
  
  # Public API view - excludes sensitive data
  define_schema(:public) do
    property :id, Integer
    property :name, String
  end
  
  # Admin view - includes everything
  define_schema(:admin) do
    property :id, Integer
    property :name, String
    property :email, String
    property :password_hash, String
    property :admin_notes, String
    property :created_at, DateTime
  end
  
  # Create payload - no id
  define_schema(:create) do
    property :name, String
    property :email, String
    property :password, String
  end
  
  # Update payload - id required, others optional
  define_schema(:update) do
    property :id, Integer
    property :name, String, optional: true
    property :email, String, optional: true
  end
end

Usage

User.json_schema           # Default schema
User.json_schema(:public)  # Public view
User.json_schema(:admin)   # Admin view
User.json_schema(:create)  # Create payload schema
User.json_schema(:update)  # Update payload schema

Schema Inheritance

Allow contexts to inherit from other contexts:

define_schema(:admin, extends: :public) do
  property :admin_notes, String
  property :created_at, DateTime
end

Validation Context Integration

Optionally tie validation to schema context:

user = User.new(name: 'John')
user.valid?                    # Validates against default schema
user.valid?(context: :create)  # Validates against :create schema

Benefits

  • DRY: Define related schemas in one place
  • Maintainability: Changes to core fields propagate to contexts (with inheritance)
  • Familiar pattern: Similar to ActiveModel Serializers, Blueprinter views
  • API flexibility: Easy versioning and role-based responses
  • Backward compatible: Default schema works as before

Implementation Considerations

  1. Store schemas in a hash: { default: schema, public: schema, ... }
  2. json_schema(context = :default) retrieves specific schema
  3. Schema inheritance via extends: option
  4. Consider lazy evaluation for inherited schemas
  5. Validation context integration with ActiveModel
  6. Clear error messages for undefined contexts

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: lowAdvanced features and enhancements

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions