通过多个编组保留json.RawMessage

Background

I'm working with JSON data that must be non-repudiable.

The API that grants me this data also has a service to verify that the data originally came from them.

As best as I can tell, they do this by requiring that the complete JSON they originally sent needs to be supplied to them inside another JSON request, with no byte changes.

Issue

I can't seem to preserve the original JSON!

Because I cannot modify the original JSON, I have carefully preserved it as a json.RawMessage when unmarshalling:

// struct I unmarshal my original data into 
type SignedResult struct {
    Raw           json.RawMessage `json:"random"`
    Signature     string          `json:"signature"`
    ...
}

// struct I marshal my data back into
type VerifiedSignatureReq {
    Raw          json.RawMessage  `json:"random"`
    Signature     string          `json:"signature"`
}

// ... getData is placeholder for function that gets my data
response := SignedResult{}
x, _ := json.Unmarshal(getData(), &response)

// do some post-processing with SignedResult that does not alter `Raw` or `Signature`

// trouble begins here - x.Raw started off as json.RawMessage...
y := json.Marshal(VerifiedSignatureReq{Raw: x.Raw, Signature: x.Signature}

// but now y.Raw is base64-encoded.

The problem is that []bytes / RawMessages are base64-encoded when marshaled. So I can't use this method, because it completely alters the string.

I'm unsure how to ensure this string is correctly preserved. I had assumed that the json.RawMessage specification in my struct would survive the perils of marshaling an already marshaled instance because it implements the Marshaler interface, but I appear mistaken.

Things I've Tried

My next attempt was to try:

// struct I unmarshal my original data into 
type SignedResult struct {
    Raw           json.RawMessage `json:"random"`
    Signature     string          `json:"signature"`
    ...
}

// struct I marshal my data back into
type VerifiedSignatureReq {
    Raw          map[string]interface{}  `json:"random"`
    Signature     string          `json:"signature"`
}

// ... getData is placeholder for function that gets my data
response := SignedResult{}
x, _ := json.Unmarshal(getData(), &response)

// do some post-processing with SignedResult that does not alter `Raw` or `Signature`

var object map[string]interface{}
json.Unmarshal(x.Raw, &object)
// now correctly generates the JSON structure.
y := json.Marshal(VerifiedSignatureReq{Raw: object, Signature: x.Signature}

// but now this is not the same JSON string as received!

The issue with this approach is that there are minor byte-wise differences in the spacing between the data. It no longer looks exactly the same when catted to a file.

I cannot use string(x.Raw) either because it escapes certain characters when marshaled with \.

You will need a custom type with its own marshaler, in place of json.RawMessage for your VerifiedSignatureReq struct to use. Example:

type VerifiedSignatureReq {
    Raw           RawMessage  `json:"random"`
    Signature     string      `json:"signature"`
}

type RawMessage []byte

func (m RawMessage) MarshalJSON() ([]byte, error) {
    return []byte(m), nil
}