Skip to content

Provide context to Unmarshaler #187

@mugabe

Description

@mugabe

For my project, I need a way to inject dependencies into an unmarshaled type or modify its behavior based on the unmarshaling context.

I'm thinking of something like this:

type Foo struct {
  intValue int
}

func (f *Foo) UnmarshalYAML(ctx context.Context, value *Node) error {
  var strValue string
  value.Decode(&strValue)

  transformer := ctx.Value("transformer").(Transformer)
  f.intValue = transformer.Transform(strValue)
}

func main() {
  ctx := context.WithValue(context.Background(), "transformer", NewTransformer())
 
  var foo Foo
  yaml.UnmarshalWithContext(ctx, []byte{"foo"}, &foo)
}

I understand that my specific needs might go against some principles, and perhaps a different approach, such as transforming the decoded configuration into another type after unmarshaling, would be more suitable.

However, I believe that providing a context.Context to an Unmarshaler could be beneficial for other reasons as well.

My idea is to introduce a new UnmarshalerWithContext interface and an UnmarshalWithContext method. This method would forward the context.Context to the UnmarshalerWithContext interface if the target type implements it.

type UnmarshalerWithContext interface {
  UnmarshalYAML(ctx context.Context, value *Node) error
}

func UnmarshalWithContext(ctx context.Context, in []byte, out any) (err error) {
  ...
}

I'm aware that there's an ongoing discussion about a new Unmarshaler interface in issue #56, so it might be worth considering adding context there.

Additionally, I like the idea of adding options to Unmarshal as proposed in issue #155. In that scenario, the context could be provided via an option rather than by introducing new methods.

I've already implemented this functionality for my own needs in my fork (Draft PR #186). While I'm quite happy with it as is, it would be perfect if something similar could get a chance to be introduced in a future v4 release.

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