I am trying to update the price of a Stripe subscription with Golang as shown here:
https://stripe.com/docs/billing/subscriptions/upgrade-downgrade
I copied and pasted the following code from the docs, but substituted in the correct Stripe key, subscription ID, and price ID:
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
stripe.Key = "sk_test_51LsirAKpk5W1QCoV3cKpwMabHz8VzurJnNNSmvBkr4zRaicCJFsz8NL7HyvJ7EC61CuKc7eHjMLHqjK1C9Xl6RpD00X5YHcRBk"
subscription, err := sub.Get("sub_49ty4767H20z6a", nil)
params := &stripe.SubscriptionParams{
CancelAtPeriodEnd: stripe.Bool(false),
ProrationBehavior: stripe.String(string(stripe.SubscriptionProrationBehaviorCreateProrations)),
Items: []*stripe.SubscriptionItemsParams{
{
ID: stripe.String(subscription.Items.Data[0].ID),
Price: stripe.String("price_CBb6IXqvTLXp3f"),
},
},
}
subscription, err = sub.Update(subscription.ID, params)
This yields the following error:
unknown field 'Price' in struct literal of type "github.com/stripe/stripe-go".SubscriptionItemsParams
Any ideas where else the Price field might go?
I solved this by specifying a Stripe version in the import by changing this:
import (
"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/customer"
"github.com/stripe/stripe-go/sub"
)
to this:
import (
stripe "github.com/stripe/stripe-go/v74"
"github.com/stripe/stripe-go/v74/customer"
"github.com/stripe/stripe-go/v74/subscription"
)
It also appears that for v74,
ProrationBehavior: stripe.String(string(stripe.SubscriptionProrationBehaviorCreateProrations)),
should be changed to
ProrationBehavior: stripe.String(string(stripe.SubscriptionSchedulePhaseProrationBehaviorCreateProrations)),
Related
I'm working on a project, with the gmail api, and I need to read a message in a thread to get some information (like message body and bottom part).
So I'm able to access my inbox, everything is set up and ready to work.
But I struggle with the next step: the only info I have to find my message/thread is the unique id you can find on the gmail url (e.g: https://mail.google.com/mail/u/0/d/xxxxxxx/#inbox/**uniqueID**)
I read the golang documentation for the google gmail api, and I couldn't find any way to get the thread or a message with just this information. Am I wrong?
If not, what could be my solution to this problem?
Scrapping? to retrieve the messageID?
Or is there another library that I could use maybe?
I tried to use the following functions:
`
message, err := srv.Users.Messages.Get(user, uniqueID).Do()
if err != nil {
return fmt.Sprintf("Unable to retrieve message: %v", err)
}
`
and
`
thread, err := srv.Users.Threads.Get(user, uniqueID).Do()
if err != nil {
return fmt.Sprintf("Unable to retrieve thread: %v", err)
}
`
But the uniqueID doesn't work for them, they're expecting the MessageID or ThreadID (IDs that you can find when you click on "Show Original" from a message in Gmail).
Unable to retrieve message: googleapi: Error 400: Invalid id value, invalidArgument
Any suggestion is welcome! ^^
Thanks
If you already have the threadId or the id (MessageID or ThreadID that you get using the method users.messages.list,) your case use the method users.messages.get to get the "Message-ID" under the payload field.
It shows in this format:
{
"name": "Message-ID",
"value": "\u003cMessage-ID\u003e"
},
To get the actual Message-ID (the one under Show original, you will need to trim \u003c at the start of the value, and \u003e at the end.
something like this maybe:
gmailMessageResposne, _ := gmail.Service.Users.Messages.Get("user#email.com", "rfc822msgid").Format("full").Do()
Reference:
Method: users.messages.list
Method: users.messages.get
I have a error model that looked like this
Error:
type: object
properties:
code:
type: string
example: missing_field
description: This field contains a string succinctly identifying the problem.
message:
type: string
example: The `first_name` field is required.
description: This field contain a plainly-written, developer-oriented explanation of the solution to the problem in complete, well-formed sentences.
more_info:
type: string
format: url
example: https://docs.api.example.com/v2/users/create_user#first_name
description: This field SHOULD contain a publicly-accessible URL where information about the error can be read in a web browser.
target:
$ref: '#/definitions/Error_target'
description: error model
I used go-swagger to generate server stub. In models/error.go file
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// swagger:model Error
type Error struct {
// This field contains a string succinctly identifying the problem.
// Example: missing_field
Code string `json:"code,omitempty"`
// This field contain a plainly-written, developer-oriented explanation of the solution to the problem in complete, well-formed sentences.
// Example: The `first_name` field is required.
Message string `json:"message,omitempty"`
// This field SHOULD contain a publicly-accessible URL where information about the error can be read in a web browser.
// Example: https://docs.api.example.com/v2/users/create_user#first_name
MoreInfo string `json:"more_info,omitempty"`
// target
Target *ErrorTarget `json:"target,omitempty"`
}
// Validate validates this error
func (m *Error) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateTarget(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *Error) validateTarget(formats strfmt.Registry) error {
...
}
The function Validate(formats strfmt.Registry) takes in a parameter called formats of type strfmt.Registry. Not sure, how and where to use this validate function and what to pass a argument for formats. Any example is greatly appreciated.
Technologies used
Go
Gorm
PostgreSQL 14.5 (In Docker container)
OpenAPI
oapi-codegen package v1.11.0
I am building an API for CRUD operations on Personas from the Shin Megami Tensei Persona spin-off series of games. I have an issue when trying to fetch data from my database using the technologies above.
Error message
sql: Scan error on column index 0, name "arcana_id": unsupported Scan, storing driver.Value type string into type *api.ArcanaID
I think the issue is that when retrieving the data it is trying to store a string inside of a *api.ArcanaID.
How can I adjust my data model so that I can pull a UUID from my DB?
I have looked at this question and it did not solve my issue because it is dealing with nil values.
I have tried changing the type of the ArcanaID from string to uuid.UUID with no success. Same error message.
Data Model - openapi.yaml
components:
schemas:
P5Arcana:
type: object
required:
- ArcanaID
properties:
ArcanaID:
$ref: "#/components/schemas/ArcanaID"
ArcanaID:
description: A universally unique identifier for identifying one of the 22 Major Arcana.
type: string
x-go-type: uuid.UUID
x-go-type-import:
path: github.com/google/uuid
x-oapi-codegen-extra-tags:
gorm: "primaryKey;unique;type:uuid;default:uuid_generate_v4()"
interface interface.go
packages databases
import (
"context"
"github.com/bradleyGamiMarques/PersonaGrimoire/api
)
type PersonaGrimoire interface {
GetPersona5ArcanaByUUID(ctx context.Context, arcanaUUID api.ArcanaID) (arcana api.P5Arcana, err error)
}
interfaceimpl interfaceimpl.go
packages databases
import (
"context"
"errors"
"fmt"
"github.com/bradleyGamiMarques/PersonaGrimoire/api"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
type PersonaGrimoireImpl struct {
Gorm *gorm.DB
Logger *logrus.Logger
}
func (p *PersonaGrimoireImpl) GetPersona5ArcanaByUUID(ctx context.Context, arcanaUUID api.ArcanaID) (arcana api.P5Arcana, err error) {
err = p.Gorm.WithContext(ctx).Model(&api.P5Arcana{ArcanaID: arcana.ArcanaID}).Where(&api.P5Arcana{ArcanaID: arcanaUUID}).First(&arcana).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
p.Logger.Warnf("Attempted to get Persona 5 Arcana by ID that does not exist. Error: %s", err.Error())
return api.P5Arcana{}, fmt.Errorf("attempted to get Persona 5 Arcana by ID that does not exist Error: %w", err)
}
}
return arcana, nil
}
Implementation code
// Check if ID exists
// Calls GetPersona5ArcanaByUUID()
// Return result
Thank you to Jamie Tanna at https://www.jvt.me/posts/2022/07/12/go-openapi-server/.
Their solution involved not using the github.com/google/uuid package and instead used the openapi_types.UUID type.
This was done by defining the schema as such.
ArcanaID:
description: A universally unique identifier for identifying one of the 22 Major Arcana.
type: string
format: uuid
pattern: "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}"
x-oapi-codegen-extra-tags:
gorm: "type:uuid;primaryKey"
This results in generated code that looks like
// ArcanaID A universally unique identifier for identifying one of the 22 Major Arcana.
type ArcanaID = openapi_types.UUID
I am able to add "Weighted" A records for the AWS Route53 using the API, using [Weight: aws.Int64(weight)], it works great using the code below. But how to add "Simple" A record - I did not see an option for Simple?
params := &route53.ChangeResourceRecordSetsInput{
ChangeBatch: &route53.ChangeBatch{ // Required
Changes: []*route53.Change{ // Required
{ // Required
Action: aws.String("UPSERT"), // Required
ResourceRecordSet: &route53.ResourceRecordSet{ // Required
Name: aws.String(name), // Required
Type: aws.String("A"), // Required
ResourceRecords: []*route53.ResourceRecord{
{ // Required
Value: aws.String(target), // Required
},
},
TTL: aws.Int64(TTL),
//Region: aws.String("us-east-1"),
Weight: aws.Int64(weight),
SetIdentifier: aws.String("-"),
},
},
},
Comment: aws.String("Sample update."),
},
HostedZoneId: aws.String(zoneId), // Required
}
A 'Simple' record is just a phrasing inside the Web Console. Just leave the record without any Weight or Latency flag and it will be a standard DNS record inside Route53.
See the type ResourceRecordSet documentation, required fields are marked. The rest, like Weight are optional!
https://docs.aws.amazon.com/sdk-for-go/api/service/route53/#ResourceRecordSet
Pretty much the same as using the CLI (https://aws.amazon.com/premiumsupport/knowledge-center/simple-resource-record-route53-cli/), just port the same fields to the Go struct.
after a couple of hours of searching that lead nowhere, I found that using the aws-sdk-go-v2 works well for adding a simple record, trying to not add a weight or latency flag will only result in an error while using the version 1 of the SDK, so I did this and worked fine:
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
// handle error
return err
}
client := route53.NewFromConfig(cfg)
params := &route53.ChangeResourceRecordSetsInput{
ChangeBatch: &types.ChangeBatch{
Changes: []types.Change{
{
Action: types.ChangeActionUpsert,
ResourceRecordSet: &types.ResourceRecordSet{
Name: aws.String(name),
Type: types.RRTypeCname,
ResourceRecords: []types.ResourceRecord{
{
Value: aws.String(target),
},
},
TTL: aws.Int64(60),
},
},
},
},
HostedZoneId: aws.String(zoneId),
}
output, err := client.ChangeResourceRecordSets(context.TODO(), params)
I have access to
com.amazonaws.services.lambda.runtime.Context;
object and by extension the invoked function Arn. The arn contains the account Id where the lambda resides.
My question is simple, I want the cleanest way to extract the account Id from that.
I was taking a look
com.amazon.arn.ARN;
It has a whole bunch of stuff, but no account ID (which i presume is due to the fact that not all arns have account ids ?)
I want to cleanly extract the account Id, without resorting to parsing the string.
If your lambda is being used as an API Gateway proxy lambda, then you have access to event.requestContext.accountId (where event is the first parameter to your handler function).
Otherwise, you will have to split the ARN up.
From the AWS documentation about ARN formats, here are the valid Lambda ARN formats:
arn:aws:lambda:region:account-id:function:function-name
arn:aws:lambda:region:account-id:function:function-name:alias-name
arn:aws:lambda:region:account-id:function:function-name:version
arn:aws:lambda:region:account-id:event-source-mappings:event-source-mapping-id
In all cases, account-id is the 5th item in the ARN (treating : as a separator). Therefore, you can just do this:
String accountId = arn.split(":")[4];
You no longer need to parse the arn anymore, sts library has introduced get_caller_identity for this purpose.
Its an overkill, but works!.
Excerpts from aws docs.
python
import boto3
client = boto3.client('sts')
response = client.get_caller_identity()['Account']
js
/* This example shows a request and response made with the credentials for a user named Alice in the AWS account 123456789012. */
var params = {
};
sts.getCallerIdentity(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
/*
data = {
Account: "123456789012",
Arn: "arn:aws:iam::123456789012:user/Alice",
UserId: "AKIAI44QH8DHBEXAMPLE"
}
*/
});
More details here & here
I use this:
ACCID: { "Fn::Join" : ["", [{ "Ref" : "AWS::AccountId" }, "" ]] }
golang
import (
"github.com/aws/aws-lambda-go/lambdacontext"
)
func Handler(ctx context.Context) error {
lc, ok := lambdacontext.FromContext(ctx)
if !ok {
return errors.Errorf("could not get lambda context")
}
AwsAccountId := strings.Split(lc.InvokedFunctionArn, ":")[4]