Skip to content

encoding/json/v2 package #3683

@sonatard

Description

@sonatard

The encoding/json/v2 package release date is yet to be determined, but I think it’s a good time to start thinking about encoding/json/v2 package and its impact on gqlgen.

The encoding/json/v2 package is planned to provide functionality compatible with the encoding/json package, and it seems that the internals of the existing encoding/json package will be built using the encoding/json/v2 package.
This means that gqlgen can benefit from performance improvements without requiring any changes. So far, there are no issues.

The problem arises when gqlgen directly uses the encoding/json/v2 package. I would like to clarify the benefits and issues that may occur in that case.

Reference

golang/go#71497
https://pkg.go.dev/github.com/go-json-experiment/json

Additional Information (edit: added by Steve Coffman)

In #2842 there was a proposal to allow a pluggable JSON implementation for gqlgen. Currently the JSON marshalling cannot be easily replaced with a different implementation such asencoding/json/v2 (or other alternatives). We would like to be able to allow this to be a choice.

As in that proposal, we would add to gqlgen 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 then 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 that 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.

This will also allow us to easily add a go version build tag when encoding/json/v2 is released, such that we can immediately upgrade to it if that Go version is available.

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