Skip to content

Conversation

goccy
Copy link
Owner

@goccy goccy commented Jun 12, 2021

context.Context support for Marshaler and Unmarshaler

  • json.MarshalContext(context.Context, interface{}, ...json.EncodeOption) ([]byte, error)
  • json.NewEncoder(io.Writer).EncodeContext(context.Context, interface{}, ...json.EncodeOption) error
  • json.UnmarshalContext(context.Context, []byte, interface{}, ...json.DecodeOption) error
  • json.NewDecoder(io.Reader).DecodeContext(context.Context, interface{}) error

Then, if we implemented the following interface, callback it.

type MarshalerContext interface {
  MarshalJSON(context.Context) ([]byte, error)
}

type UnmarshalerContext interface {
  UnmarshalJSON(context.Context, []byte) error
}

Why

I thought there were situations in MarshalJSON and UnmashalJSON where I wanted to use context.Context .

For example, we consider the situation that in MarshalJSON, you want to access external middleware, get the data, and then encode it. At this time, context.Context may be required when accessing middleware, we want to use the context.Context not created inside MarshalJSON but used by the caller of json.Marshal().
I show this situation's sample code the following:

type User struct {
  ID int64
  Name string
  UserAddress UserAddressResolver
}

type UserAddressResolver func(ctx context.Context) (*UserAddress, error)
func (r UserAddressResolver) MarshalJSON() ([]byte, error) {
  ctx := context.Background() // we want to use parent context.Context but we can't get it.
  address, err := r(ctx) // fetch UserAddress data from external middleware
  if err != nil {
    return nil, err
  }
  return json.Marshal(address)
}

type UserAddress struct {
  ID int64
  UserID int64
  PostCode string
  Address string
}

u := &User{ID: 1, Name: "alice"}
u.UserAddress = func(ctx context.Context) (*UserAddress, error) {
  return db.FindUserAddressByUserID(ctx, u.ID)
}

json.Marshal(u)

In this case, there is no way to pass context.Context to MarshalJSON , so I think that an approach like json.MarshalContext is necessary.

@codecov-commenter
Copy link

Codecov Report

Merging #248 (cd7fb73) into master (ad04977) will decrease coverage by 0.11%.
The diff coverage is 56.42%.

@@            Coverage Diff             @@
##           master     #248      +/-   ##
==========================================
- Coverage   81.50%   81.38%   -0.12%     
==========================================
  Files          46       46              
  Lines       14537    14641     +104     
==========================================
+ Hits        11848    11916      +68     
- Misses       2142     2173      +31     
- Partials      547      552       +5     

@goccy goccy merged commit 5c22860 into master Jun 12, 2021
@goccy goccy deleted the feature/context branch June 12, 2021 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants