Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP/RFC] Begin custom unmarshalling for events, do not use maps #729

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 97 additions & 3 deletions event.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"strconv"
"strings"
)

// Event is the resource representing a Stripe event.
Expand All @@ -19,6 +20,20 @@ type Event struct {
Type string `json:"type"`
}

// internalEvent is used for custom unmarshalling so Data is
// unmarshalled into the correct object (Customer, Invoice, etc...)
type internalEvent struct {
Event
Data rawEventData `json:"data"`
}

// rawEventData is an interim struct holding the event data, using the event type
// we can determine what the actual EventData object should be and unmarshal Raw
type rawEventData struct {
Raw json.RawMessage `json:"object"`
PreviousAttributes map[string]interface{} `json:"previous_attributes"`
}

// EventRequest contains information on a request that created an event.
type EventRequest struct {
// ID is the request ID of the request that created an event, if the event
Expand All @@ -33,9 +48,44 @@ type EventRequest struct {

// EventData is the unmarshalled object as a map.
type EventData struct {
Object map[string]interface{}
PreviousAttributes map[string]interface{} `json:"previous_attributes"`
Raw json.RawMessage `json:"object"`
Object map[string]interface{}
Account *Account
Application *Application
Card *Card
BankAccount *BankAccount
ApplicationFee *ApplicationFee
FeeRefund *FeeRefund
Balance *Balance
Charge *Charge
Dispute *Dispute
Refund *Refund
Coupon *Coupon
Customer *Customer
Discount *Discount
Subscription *Subscription
File *File
Invoice *Invoice
InvoiceItem *InvoiceItem
IssuingAuthorization *IssuingAuthorization
IssuingCard *IssuingCard
IssuingCardholder *IssuingCardholder
IssuingDispute *IssuingDispute
IssuingTransaction *IssuingTransaction
Order *Order
PaymentIntent *PaymentIntent
Payout *Payout
Plan *Plan
Product *Product
Recipient *Recipient
ReportRun *ReportRun
Review *Review
SKU *SKU
Source *Source
SourceTransaction *SourceTransaction
Topup *Topup
Transfer *Transfer
PreviousAttributes map[string]interface{} `json:"previous_attributes"`
Raw json.RawMessage `json:"object"`
}

// EventParams is the set of parameters that can be used when retrieving events.
Expand Down Expand Up @@ -71,6 +121,50 @@ func (e *Event) GetPreviousValue(keys ...string) string {
return getValue(e.Data.PreviousAttributes, keys)
}

func (e *Event) UnmarshalJSON(data []byte) error {
var internal internalEvent
if err := json.Unmarsal(data, &internal); err != nil {
return err
}
switch internal.Type {
case "account.updated":
var account Account
if err := json.Unmarshal([]byte(internal.Data.Raw), &account); err != nil {
return err
}
*e = internal.Event
e.Data.Account = &account
case "account.application.authorized", "account.application.deauthorized":
var application Application
if err := json.Unmarshal([]byte(internal.Data.Raw), &application); err != nil {
return err
}
*e = internal.Event
e.Data.Application = &application
case "account.external_account.created", "account.external_account.deleted", "account.external_account.updated":
// find bank_account, get the type
if strings.Contains(string(internal.Data.Raw), "bank_account") {
var bankAccount BankAccount
if err := json.Unmarshal([]byte(internal.Data.Raw), &bankAccount); err != nil {
return err
}
*e = internal.Event
e.Data.BankAccount = &bankAccount
} else {
var card Card
if err := json.Unmarshal([]byte(internal.Data.Raw), &card); err != nil {
return err
}
*e = internal.Event
e.Data.Card = &card
}
}
// transfer other fields
e.Data.Raw = internal.Data.Raw
e.Data.PreviousAttributes = internal.Data.PreviousAttributes
return nil
}

// UnmarshalJSON handles deserialization of the EventData.
// This custom unmarshaling exists so that we can keep both the map and raw data.
func (e *EventData) UnmarshalJSON(data []byte) error {
Expand Down