Skip to content

Instantly share code, notes, and snippets.

@ulexxander
Created February 21, 2022 14:38
Show Gist options
  • Save ulexxander/43c6d3041321c38923ad0fc45cfdfcb2 to your computer and use it in GitHub Desktop.
Save ulexxander/43c6d3041321c38923ad0fc45cfdfcb2 to your computer and use it in GitHub Desktop.
Example of using Go json.RawMessage to unmarshal JSON field in struct based on another field determining its expected type.
package twofactorunmarshal
import (
"encoding/json"
"fmt"
"testing"
"github.com/pkg/errors"
)
type Event string
const (
EventRegister Event = "register"
EventOrder Event = "order"
)
type RegisterData struct {
Username string
Password string
}
type OrderData struct {
Currency string
Amount float64
}
type Message struct {
Event Event
Data json.RawMessage
}
func handleMessage(m *Message) error {
switch m.Event {
case EventRegister:
var data RegisterData
if err := json.Unmarshal(m.Data, &data); err != nil {
return errors.Wrap(err, "unmarshaling FormOnSubmitData")
}
return handleRegister(&data)
case EventOrder:
var data OrderData
if err := json.Unmarshal(m.Data, &data); err != nil {
return errors.Wrap(err, "unmarshaling InputOnChangeData")
}
return handleOrder(&data)
default:
return errors.Errorf("unknown event: %s", m.Event)
}
}
func handleRegister(data *RegisterData) error {
if data.Username == "" {
return errors.New("username cannot be empty")
}
if len(data.Password) < 6 {
return errors.New("password is too short")
}
fmt.Println("registered user!")
return nil
}
func handleOrder(data *OrderData) error {
if data.Currency == "" {
return errors.New("currency cannot be empty")
}
if data.Amount < 0 {
return errors.New("amount can not be negative")
}
fmt.Println("order created successfully!")
return nil
}
func TestUnmarshal(t *testing.T) {
t.Run("register", func(t *testing.T) {
messageJSON := []byte(`{"event": "register", "data": {"username": "alex", "password": "123456"}}`)
var m Message
err := json.Unmarshal(messageJSON, &m)
if err != nil {
t.Fatal(err)
}
err = handleMessage(&m)
if err != nil {
t.Fatal(err)
}
})
t.Run("order invalid data", func(t *testing.T) {
messageJSON := []byte(`{"event": "order", "data": [1,2,3]}`)
var m Message
err := json.Unmarshal(messageJSON, &m)
if err != nil {
t.Fatal(err)
}
err = handleMessage(&m)
if err == nil {
t.Fatal("expected to fail because data is in unexpected structure")
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment