英文:
How do i properly get struct items from stripe subscription response object?
问题
我正在尝试从Stripe订阅响应对象的结构中获取一些数据。这是响应对象结构的链接stribe subscription object。
这是我目前的代码和我想要做的事情:
type SubscriptionDetails struct {
CustomerId string `json:"customer_id"`
SubscriptionId string `json:"subscription_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.ID
data.SubscriptionId = result.ID
data.StartAt = time.Unix(result.CurrentPeriodStart, 0)
data.EndAt = time.Unix(result.CurrentPeriodEnd, 0)
data.Interval = result.Items.Data[0].Price.Recurring.Interval
data.Plan = result.Items.Data[0].Price.Nickname
data.SeatCount = result.Items.Data[0].Quantity
data.PricePerSeat = float64(result.Items.Data[0].Price.UnitAmount) / 100
return data, nil
}
对于data.CustomerId
和data.PricePerSeat
,你可以使用result.Customer.ID
和result.Items.Data[0].Price.UnitAmount
来获取数据。
更新:
这是来自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"`
}
英文:
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"`
}
答案1
得分: 1
看到你提到的三个错误:
cannot use result.CurrentPeriodStart (type int64) as type time.Time in assignment
result.CurrentPeriodStart
的类型是 int64,而你试图将其赋值给类型为 time.Time
的字段,这显然会失败。
API 以 Unix 格式发送时间,你需要解析它以将其转换为 time.Time
。对其他时间字段也要进行相同的操作。
data.StartAt = time.Unix(result.CurrentPeriodStart, 0)
cannot use result.Customer (type *stripe.Customer) as type string in assignment
与上面类似,result.Customer
的类型是 *stripe.Customer
,而你试图将其赋值给类型为 string
的字段。Customer ID 是 Customer
结构体内的一个字段。
data.CustomerId = result.Customer.ID
result.Items.Data.price undefined (type []*stripe.SubscriptionItem has no field or method price)
stripe.SubscriptionItem
结构体没有 price
字段。我不确定你想要什么。建议阅读订阅对象文档。
英文:
Looking at the 3 errors you have mentioned
cannot use result.CurrentPeriodStart (type int64) as type time.Time in assignment
Type of result.CurrentPeriodStart
is int64 and you are trying to set it into a field of type time.Time
, which will obviously fail.
The API is sending the time in unix format, which you need to parse to get it into time.Time. Do this for other time fields also
data.StartAt = time.Unix(result.CurrentPeriodStart, 0)
cannot use result.Customer (type *stripe.Customer) as type string in assignment
Similar issue as above, the field result.Customer
is of type *stripe.Customer
while you are trying to set it into a field of type string
. Customer ID is a field inside the struct Customer
data.CustomerId = result.Customer.ID
result.Items.Data.price undefined (type []*stripe.SubscriptionItem has no field or method price)
stripe.SubscriptionItem
struct does not have a field price
. I am not sure what you want here. I suggest reading the subscriptions object documentation.
答案2
得分: 1
要访问价格 result.Items.Data[0].Price.UnitAmount
如果你使用调试器,只需在 sub.New
行后设置一个断点,然后探索结果变量的内容。
英文:
To access the price result.Items.Data[0].Price.UnitAmount
If you use a debugger, just put a breakpoint after the sub.New
line and explore the content of the result variable
答案3
得分: 1
首先让我们来看一下代码的内部工作原理,返回的内容,然后逐个解决问题。
当我们使用params
调用sub.New()
方法时,它会返回Subscription
类型。
注意:我只会显示类型的有限定义,因为添加完整的结构会使答案变得冗长,并且与问题的上下文无关。
让我们来看一下Subscription
类型:
type Subscription struct {
...
// 当前周期开始的时间,该订阅已开具发票。
CurrentPeriodStart int64 `json:"current_period_start"`
// 拥有该订阅的客户的ID。
Customer *Customer `json:"customer"`
...
// 订阅项列表,每个项都附有价格。
Items *SubscriptionItemList `json:"items"`
...
}
让我们先看一下第一个错误:
cannot use result.CurrentPeriodStart (type int64) as type time.Time in assignment
根据Subscription
类型,我们可以看到CurrentPeriodStart
的类型是int64
,而你正在尝试将其设置为SubscriptionDetails
类型的StartAt
字段,而SubscriptionDetails
类型的StartAt
字段的类型是time.Time
。由于类型不同,一个类型不能赋值给另一个类型,为了解决这个问题,我们需要显式地将其转换为time.Time
,可以按照以下方式进行转换:
data.StartAt = time.Unix(result.CurrentPeriodStart, 0)
time.Unix
方法从传递的int64
值创建time.Time
类型并返回,我们可以将其赋值给StartAt
字段。
现在让我们继续处理第二个错误:
cannot use result.Customer (type *stripe.Customer) as type string in assignment
根据Subscription
的定义,Customer
字段的类型是*Customer
,而不是字符串类型。由于你正在尝试将*Customer
类型赋值给字符串类型的CustomerId
字段,这是不可能的,导致了上述错误。正确的数据不在这里,正确的数据在*Customer
类型内部的ID
字段中,可以按照以下方式检索到正确的数据:
data.CustomerId = result.Customer.ID
让我们继续处理最后一个错误:
result.Items.Data.price undefined (type []*stripe.SubscriptionItem has no field or method price)
再次查看Subscription
的定义,我们可以看到Items
字段的类型是*SubscriptionItemList
类型,如果我们查看*SubscriptionItemList
的定义:
type SubscriptionItemList struct {
APIResource
ListMeta
Data []*SubscriptionItem `json:"data"`
}
它包含一个名为Data
的字段,而Data
的类型是[]*SubscriptionItem
,请注意它是*SubscriptionItem
的切片[]
,这就是错误的原因,因为Data
字段是*SubscriptionItem
的切片,我们可以按照以下方式解决这个问题:
data.PricePerSeat = result.Items.Data[0].price.UnitAmount
还有一些可能出现的错误,我想指出,请继续阅读下面的内容以解决这些问题。
现在让我们来看一下*SubscriptionItem
的定义:
type SubscriptionItem struct {
...
Price *Price `json:"price"`
...
}
它包含Price
字段,请注意名称以大写字母开头,在共享代码中,它以小写字母引用,这可能会导致另一个问题。最后,如果我们查看Price
的定义:
type Price struct {
...
// 要收取的单位金额,如果可能的话,表示为整数。仅在`billing_scheme=per_unit`时设置。
UnitAmount int64 `json:"unit_amount"`
// 要收取的单位金额,表示为最多12位小数的十进制字符串。仅在`billing_scheme=per_unit`时设置。
UnitAmountDecimal float64 `json:"unit_amount_decimal,string"`
...
}
它包含UnitAmount
字段,这是我们正在使用的字段,但是这里有一个问题,UnitAmount
的类型是int64
,而PricePerSeat
的类型是float64
,将不同类型赋值给彼此将再次导致错误。你可以将int64
转换为float64
,或者更好的是,你可以使用Price
类型中的UnitAmountDecimal
字段,该字段以float64
格式包含相同的数据,这样可以减少在使用UnitAmount
字段时必须进行的显式转换。因此,根据上述解释,我们得到以下解决方案:
data.PricePerSeat = result.Items.Data[0].Price.UnitAmountDecimal
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论