Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do i properly get struct items from stripe subscription response object?

I am trying to grab some data from the struct of the stripe response objects for subscriptions. Here is link to the structure of the response object stribe subscription object

Here is what i have and what am trying to do

type SubscriptionDetails struct {
    CustomerId             string  `json:"customer_id"`
    SubscritpionId         string  `json:"subscritpion_id"`
    StartAt                time.Time  `json:"start_at"`
    EndAt                  time.Time  `json:"end_at"`
    Interval               string  `json:"interval"`
    Plan                   string  `json:"plan"`
    PlanId                 string  `json:"plan_id"`
    SeatCount              uint8  `json:"seat_count"`
    PricePerSeat           float64  `json:"price_per_seat"`
}



func CreateStripeSubscription(CustomerId string, planId string) (*SubscriptionDetails, error) {

    stripe.Key = StripeKey

    params := &stripe.SubscriptionParams{
    Customer: stripe.String(CustomerId),
    Items: []*stripe.SubscriptionItemsParams{
        &stripe.SubscriptionItemsParams{
        Price: stripe.String(planId),
        },
    },
    }
    result, err := sub.New(params)

    if err != nil {
        return nil, err
    }

    data := &SubscriptionDetails{}

    data.CustomerId           = result.Customer
    data.SubscritpionId       =  result.ID
    data.StartAt              =  result.CurrentPeriodStart
    data.EndAt                =  result.CurrentPeriodEnd
    data.Interval             =  result.Items.Data.Price.Recurring.Interval
    data.Plan                 =  result.Items.Data.Price.Nickname
    data.SeatCount            =  result.Items.Data.Quantity
    data.PricePerSeat         =  result.Items.Data.Price.UnitAmount


    return data, nil    
}

there are some items that are easy to get directly like ID field i got easily with result.ID and no complaints but for other items here are the error messages am getting

cannot use result.CurrentPeriodStart (type int64) as type time.Time in assignment
...
cannot use result.Customer (type *stripe.Customer) as type string in assignment
...
result.Items.Data.price undefined (type []*stripe.SubscriptionItem has no field or method price)

So how do i get the data for data.CustomerId and data.PricePerSeat?

UPDATE:

here is structure of the subscription object from stripe

type FilesStripeCreateSubscription struct {
    ID                    string      `json:"id"`
    CancelAt             interface{}   `json:"cancel_at"`
    CancelAtPeriodEnd    bool          `json:"cancel_at_period_end"`
    CanceledAt           interface{}   `json:"canceled_at"`
    CurrentPeriodEnd     int64         `json:"current_period_end"`
    CurrentPeriodStart   int64         `json:"current_period_start"`
    Customer             string        `json:"customer"`
    Items                struct {
            Data []struct {
                    ID                string      `json:"id"`
                    BillingThresholds interface{} `json:"billing_thresholds"`
                    Created           int64       `json:"created"`
                    Metadata          struct {
                    } `json:"metadata"`
                    Object string `json:"object"`
                    Price  struct {
                            ID               string      `json:"id"`
                            Active           bool        `json:"active"`
                            Currency         string      `json:"currency"`
                            CustomUnitAmount interface{} `json:"custom_unit_amount"`
                            Metadata         struct {
                            } `json:"metadata"`
                            Nickname  string `json:"nickname"`
                            Object    string `json:"object"`
                            Product   string `json:"product"`
                            Recurring struct {
                                    AggregateUsage interface{} `json:"aggregate_usage"`
                                    Interval       string      `json:"interval"`
                                    IntervalCount  int64       `json:"interval_count"`
                                    UsageType      string      `json:"usage_type"`
                            } `json:"recurring"`
                            TaxBehavior       string      `json:"tax_behavior"`
                            TiersMode         interface{} `json:"tiers_mode"`
                            TransformQuantity interface{} `json:"transform_quantity"`
                            Type              string      `json:"type"`
                            UnitAmount        int64       `json:"unit_amount"`
                            UnitAmountDecimal int64       `json:"unit_amount_decimal,string"`
                    } `json:"price"`
                    Quantity     int64         `json:"quantity"`
                    Subscription string        `json:"subscription"`
                    TaxRates     []interface{} `json:"tax_rates"`
            } `json:"data"`
    } `json:"items"`
}
like image 742
uberrebu Avatar asked Oct 19 '25 20:10

uberrebu


1 Answers

Lets first go over the code which works under the hood, what is being returned and then we look at the problems one at a time.

When we call sub.New() method with params it returns Subscription type

Note: I will only show limited definition for types since adding the complete structure will make the answer big and not specific to the question context

Lets Look Subscription type

type Subscription struct {
  ...
  // Start of the current period that the subscription has been invoiced for.
  CurrentPeriodStart int64 `json:"current_period_start"`
  // ID of the customer who owns the subscription.
  Customer *Customer `json:"customer"`
  ...
  // List of subscription items, each with an attached price.
  Items *SubscriptionItemList `json:"items"`
  ...
}

Let looks over the first error

cannot use result.CurrentPeriodStart (type int64) as type time.Time in assignment

According to the Subscription type we can see CurrentPeriodStart is of type int64 while you are trying to set it to StartAt field of SubscriptionDetails type which is of type time.Time since the types are different one type cannot be assigned to other, to solve the issue we need to explicitly convert it to time.Time which can be done as follows:

data.StartAt = time.Unix(result.CurrentPeriodStart, 0)

time.Unix method creates time.Time type from the passed int64 value and return which we can assign to StartAt field

Now lets move on to the second error

cannot use result.Customer (type *stripe.Customer) as type string in assignment

As we can see from Subscription definition Customer field is of type *Customer it is not string type since you are trying to assign *Customer type to CustomerId field of string type which is not possible that causes the above error, referred data is incorrect then where is the correct data the correct data is available inside *Customer type withing ID field which can be retrieved as follows

data.CustomerId = result.Customer.ID

Lets go over the last error

result.Items.Data.price undefined (type []*stripe.SubscriptionItem has no field or method price)

Again if we look at Subscription definition we can see Items field is of type *SubscriptionItemList type and if we look at *SubscriptionItemList definition

type SubscriptionItemList struct {
    APIResource
    ListMeta
    Data []*SubscriptionItem `json:"data"`
}

It contains a field name Data and Data is of type []*SubscriptionItem notice it is slice [] of *SubscriptionItem, which is the cause of the error since Data field is slice of *SubscriptionItem we can solve the problem as below:

data.PricePerSeat = result.Items.Data[0].price.UnitAmount

There are few more errors which can occur that I would like to point out please continue reading below to solve those issue

Now lets look at *SubscriptionItem definition

type SubscriptionItem struct {
  ...
  Price *Price `json:"price"`
  ...
}

It contains Price field notice the name starts with capital letter and in shared code it is referred with small letter which can cause another issue and finally if we look at Price definition

type Price struct {
  ...
  // The unit amount in %s to be charged, represented as a whole integer if possible. Only set if `billing_scheme=per_unit`.
  UnitAmount int64 `json:"unit_amount"`

  // The unit amount in %s to be charged, represented as a decimal string with at most 12 decimal places. Only set if `billing_scheme=per_unit`.
  UnitAmountDecimal float64 `json:"unit_amount_decimal,string"`
  ...
}

It contains UnitAmount field which is what we are using, but there is a catch here UnitAmount is of type int64 but PricePerSeat is of type float64 assigning different type to each other will again cause error so either you can convert int64 to float64 or even better you can use UnitAmountDecimal field available within Price type containing the same data in float64 format which will reduce the explicit conversion that we would have to do when using UnitAmount field, so as per the explanation we get below solution

data.PricePerSeat = result.Items.Data[0].Price.UnitAmountDecimal
like image 200
Chandan Avatar answered Oct 21 '25 13:10

Chandan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!