Skip to content

Typed response models with compile-time schema generation #314

@bburda

Description

@bburda

Problem

OpenAPI schemas are defined separately from handler response construction. There is no compile-time or runtime enforcement that a handler's JSON output matches its declared schema. This leads to silent drift - schemas say one thing, handlers return another, and generated clients break.

PR #313 fixed all current mismatches and added a SchemaConsistencyTest safety net, but the root cause remains: schemas and serialization are two independent code paths.

Proposed solution

Introduce typed C++ response model structs that own both serialization and schema generation:

struct ConfigurationMetaData {
  std::string id, name, type;

  nlohmann::json to_json() const {
    return {{"id", id}, {"name", name}, {"type", type}};
  }

  static nlohmann::json openapi_schema() {
    return {{"type", "object"},
            {"properties",
             {{"id", {{"type", "string"}}},
              {"name", {{"type", "string"}}},
              {"type", {{"type", "string"}}}}},
            {"required", {"id", "name", "type"}}};
  }
};

Handlers construct the struct, not raw JSON. Route registration extracts the schema from the type. Single source of truth - if the struct changes, both the response and the schema change together.

Scope

  • Define response model structs for each resource type (Configuration, Operation, Fault, Data, Trigger, Subscription, Lock, Script, BulkData, Update, Health, Auth)
  • Migrate handlers incrementally (one resource type per PR)
  • Register schemas via model types instead of manual component_schemas() entries
  • Remove SchemaBuilder static schema methods as models take over

Alternatives considered

  • Shared field constants (struct with static constexpr field names used by both schema and handler) - less invasive but still allows structural divergence
  • Runtime validation (validate response JSON against schema before sending) - catches mismatches but only at test/runtime, adds overhead

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions