Skip to content

[Proposal] Allow passing a custom json marshal/unmarshal implementation #2842

Description

@ManiacMaxo

Currently the json marshalling cannot be easily replaces with a different implementation like https://github.com/goccy/go-json or https://github.com/json-iterator/go. The only way to do so would be to copy the transport implementations and inject the json marshaller there.

I propose an API that accepts a custom implementation supplied directly to the transport at fields:

type Decoder interface {
	Decode(v interface{}) error
	UseNumber()
}

type Json interface {
	Marshal(v interface{}) ([]byte, error)
	NewDecoder(r io.Reader) Decoder
}

type POST struct {
	// Map of all headers that are added to graphql response. If not
	// set, only one header: Content-Type: application/json will be set.
	ResponseHeaders map[string][]string
	Json            Json // Json being an interface so it can be implemented however the user wants
}

The library can supply a default implementation based on encoding/json:

var DefaultJson Json = jsonImpl{}

type jsonImpl struct{}

func (jsonImpl) Marshal(v interface{}) ([]byte, error) {
	return json.Marshal(v)
}

func (jsonImpl) NewDecoder(r io.Reader) Decoder {
	return json.NewDecoder(r)
}

Since there already exists a file that handles most json marshalling it can be updated to accept the json implementation and fallback if one is not supplied:

func writeJson(json Json, w io.Writer, response *graphql.Response) {
	if json == nil {
		json = DefaultJson
	}
	b, err := json.Marshal(response)
	if err != nil {
		panic(err)
	}
	w.Write(b)
}

This will add a slight overhead of checking for the implementation but will not break existing codebases.

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