Skip to content

struct_to_gts_schema: gts_type field blocks Deserialize for structs #72

@striped-zebra-dev

Description

@striped-zebra-dev

Problem

The struct_to_gts_schema proc macro injects a gts_type: GtsSchemaId field into every struct it processes, with #[serde(skip_serializing)]. This means:

  1. Serialization: gts_type is correctly omitted from JSON output
  2. Deserialization: serde still expects gts_type in the JSON input, causing missing field "gts_type" errors

The macro generates both Serialize and Deserialize impls, but skip_serializing only covers one direction.

Impact

Any struct using #[struct_to_gts_schema] cannot be deserialized from JSON without a workaround. This blocks use cases like:

  • Round-trip serialization/deserialization (e.g., CanonicalError → Problem → CanonicalError)
  • Deserializing context types from HTTP response bodies in SDK clients
  • Testing with JSON fixtures

Current Workaround

Adding default = "dummy_gts_schema_id" to the serde attribute on every struct, with a function that constructs a placeholder GtsSchemaId via serde_json::from_value. This is fragile and pollutes consumer code.

Proposed Fix

Change the macro to emit #[serde(skip)] (which handles both serialization and deserialization) on the gts_type field. This requires one of:

  • Option A: Implement Default for GtsSchemaId (e.g., GtsSchemaId("") or GtsSchemaId::empty()) — then #[serde(skip)] works automatically
  • Option B: Have the macro emit #[serde(skip_serializing, default = "...")] with a generated default function per struct (using Self::gts_schema_id().clone())
  • Option C: Remove the gts_type instance field entirely — the schema ID is already available as Self::gts_schema_id() via the GtsSchema trait. The field is always #[allow(dead_code)] and never read at runtime.

Option C is the cleanest — the field has no runtime purpose.

Environment

  • gts / gts-macros: 0.8.2
  • serde: 1.x

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions