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:
- Serialization:
gts_type is correctly omitted from JSON output
- 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
Problem
The
struct_to_gts_schemaproc macro injects agts_type: GtsSchemaIdfield into every struct it processes, with#[serde(skip_serializing)]. This means:gts_typeis correctly omitted from JSON outputgts_typein the JSON input, causingmissing field "gts_type"errorsThe macro generates both
SerializeandDeserializeimpls, butskip_serializingonly covers one direction.Impact
Any struct using
#[struct_to_gts_schema]cannot be deserialized from JSON without a workaround. This blocks use cases like:CanonicalError → Problem → CanonicalError)Current Workaround
Adding
default = "dummy_gts_schema_id"to the serde attribute on every struct, with a function that constructs a placeholderGtsSchemaIdviaserde_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 thegts_typefield. This requires one of:DefaultforGtsSchemaId(e.g.,GtsSchemaId("")orGtsSchemaId::empty()) — then#[serde(skip)]works automatically#[serde(skip_serializing, default = "...")]with a generated default function per struct (usingSelf::gts_schema_id().clone())gts_typeinstance field entirely — the schema ID is already available asSelf::gts_schema_id()via theGtsSchematrait. 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.2serde: 1.x