Coder Social home page Coder Social logo

stripe-go's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stripe-go's Issues

SetHTTPClient and other global setters need locking

The Go runtime does not guarantee that pointer swaps are atomic (e.g. many non-x86 processors). In order for these globals to be used, the code needs to use locks or atomic loads and swaps to pull these objects out without racing.

Honestly, it would be preferable to have these as default clients etc. that can't be changed and just make it easier to build out clients that do not use the default HTTP client. Currently, it's very difficult to not use the default HTTP client, etc., because of the complicated use of BackendConfiguration, SupportedBackend, Backend, and even Backends types in this API.

Is DefaultSource missing on the CustomerParams?

I'm trying to do the following:

  • create a new card (using the card creation API endpoint)
  • make the new card the default (by using the customer update API epndoint).

According to the documentation (https://stripe.com/docs/api#update_customer) there is an optional default_source parameter, however don't see it on the customer params: https://github.com/stripe/stripe-go/blob/master/customer.go#L7-L17

Is this named something else? Is there another preferred way of doing this?

UPDATE: It looks like this used to be default_card, but that this was deprecated and then removed in the API change of 2015-02-18. I'll submit a PR to change DefaultCard to DefaultSource, since it seems like it is not there intentionally.

Iter Panic

Given a completely new and clean Stripe account the following code:

params := &stripe.InvoiceListParams{
    Customer: "stripeId", // valid customer.ID
}
i := invoice.List(params)
for !i.Stop() {
    inv, err := i.Next()
    if err != nil {
        // handle error
    }
} 

Bails with the following:

panic: interface conversion: interface is nil, not *stripe.Invoice

The offending line:

github.com/stripe/stripe-go/invoice/client.go:257

This seems to fail for all other iterators as well.

Cannot set Customer.CardParams.Token when creating a customer

Lost a bit of time to this: rather than setting Customer.Token to set the token for a card I was creating a CardParams value and setting its Token field and scratching my head about why it doesn't work. The CustomerClient.Create method doesn't look for this, but maybe it should?

Create customer | With subscription

{"type":"invalid_request_error","message":"Invalid timestamp: must be an integer Unix timestamp in the future.","param":"trial_end"}

It would be good if:

&CustomerParams{TrialEndNow: true}

Thanks.

Client `Init` mutates global state.

Calling Client.Init with a non-nil httpClient mutates the global httpClient. This could cause confusing and unexpected behavior. Per a discussion with @cosn, we're simply going to remove the httpClient parameter and global getter/setter. To pass a custom httpClient, pass a custom backend created with NewInternalBackend.

BankAccountParams Token Missing

According to Create Recipient Documentation, I should be able to pass a Stripe.js bank account token like so:

Bank:  &stripe.BankAccountParams{Token: token}

in the same manner as:

Card:  &stripe.CardParams{Token: token},

However, Token is not a defined field in stripe.BankAccountParams. Has it simply not been added yet?

NewIdempotencyKey repeats value for leap seconds

NewIdempotencyKey is not actually idempotent. If time moves backwards (as it will to every machine running NTP this June when the leap second hits), this code will produce the same key many times. https://github.com/stripe/stripe-go/blob/master/params.go#L58

Instead, just pull 128 bits from crypto/rand.Read. That will be enough randomness to not collide for the lifetime of the universe.

The previous leap second in 2012 did not go well. http://www.wired.com/2012/07/leap-second-bug-wreaks-havoc-with-java-linux/

disable log messages?

Is there a way to disable/redirect Stripe logging? Specifically the "Requesting..." message when an API request goes out.

I tried putting this in my own code

log.SetOutput(ioutil.Discard)

but this disables all logging, not just from this library.

Invalid memory address when json.Marshalling a charge response

I'm trying to save the charge response as an audit log in postgresql as a JSON field but whenever I try to json.Marshal the object I get an nil pointer reference.

The trace output shows the error as originating here: github.com/stripe/stripe-go/payment_source.go:165 which is the MarshalJSON() method on the PaymentSource

It seems to be caused because c.Card.Customer is nil here.

I've created a work around for it that satisfies my use-case in which in the MarshalJSON method I check for the c.Card.Customer object and only assign the Customer if it's set:

func (s *PaymentSource) MarshalJSON() ([]byte, error) {
    var target interface{}

    switch s.Type {
    case PaymentSourceBitcoinReceiver:
        target = struct {
            Type PaymentSourceType `json:"object"`
            *BitcoinReceiver
        }{
            Type:            s.Type,
            BitcoinReceiver: s.BitcoinReceiver,
        }
    case PaymentSourceCard:
        var customerID *string
        if s.Card.Customer != nil {
            customerID = &s.Card.Customer.ID
        }

        target = struct {
            Type     PaymentSourceType `json:"object"`
            Customer *string           `json:"customer"`
            *Card
        }{
            Type:     s.Type,
            Customer: customerID,
            Card:     s.Card,
        }
    case "":
        target = s.ID
    }

    return json.Marshal(target)
}

My code:

sc := &client.API{}
sc.Init(stripeCredentials.TestKey, nil)

chargeParams := &stripe.ChargeParams{
    Amount:    uint64(order.TotalIncTax * 100),
    Currency:  currency.GBP,
    Desc:      "Payment To " + store.Name + " for Your Order #" + strconv.FormatInt(order.ExternalID, 10),
    NoCapture: true,
}

chargeParams.Params.IdempotencyKey = stripe.NewIdempotencyKey()

chargeParams.SetSource(&stripe.CardParams{
    Number:   cardDetails.CardNumber,
    Month:    cardDetails.ExpiryMonth,
    Year:     cardDetails.ExpiryYear,
    CVC:      cardDetails.CVC,
    Address1: order.BillingAddress.Line1,
    Address2: order.BillingAddress.Line2,
    City:     order.BillingAddress.City,
    State:    order.BillingAddress.State,
    Zip:      order.BillingAddress.PostalCode,
    Country:  order.BillingAddress.CountryISO,
})

charge, err := sc.Charges.New(chargeParams)

// This method appends the passed value to the transaction AuditLog field which is then json.Marshalled()
// This call only fails if the charge object is passed in. Anything else works
transaction.AddAuditLog(&TransactionAuditLog{
    Error: err,
    Response: charge,
})

Consider gopkg.in versioning

The readme mentions go's lack of package versioning. gopkg.in provides such API versioning that may be useful. This may have already been considered and rejected, and the reasons would be interesting to hear. If not, is it worth adding?

No way to set zero (0) Quantity subscription from Golang client

This page https://stripe.com/docs/subscriptions claims that:
"If quantity is set to zero, the subscription will act like a free plan, creating invoices but not charging customers."

This in fact works when you call the API with something like CURL.

However, when omitted, the stripe API doc says "quantity optional, default is 1".

In Go zero (0) is the default value for an uninitialized number. As such stripe.SubParams.Quantity being set to zero means "un-initialized". Which gets elided from the request that is made. This means you cannot set a zero quantity subscription from the golang client. Trying to do so makes a subscription of quantity 1 since it falls back to the default.

Which is unfortunate because we have need for such a thing :).

Expose logger

I have a use case where I need to track transactions going across my application. Each request has a unique ID which I attach to the log entry. I propose that instead of using the log package as it is seen here, that a Logger variable be added as a package level variable to stripe.go where the whole package could log to instead. This would allow runtime customization of the logging prefix, and level to a much higher degree then the stripe.LogLevel variable gives.

Could create a new logger in an init function as:

var Logger *log.Logger

func init() {
    ...
    Logger = log.New(os.Stderr, "", log.LstdFlags)
    ...
}

Then customizations could be done with stripe.Logger.SetPrefix or stripe.Logger.SetFlags.

Go docs need more detail, especially on Get client calls.

It's not really clear what purpose the Params serve when passing them into the various Get methods. With Customers.Get() you can pass nil for CustomerParams. But with Subs.Get() if you pass nil for SubParams you get a panic.

It's not obvious from the godoc that you need to create a SubParams with the Customer field set to a customer ID. It is a little more clear in the online Stripe docs but I wasn't looking at those. The stripe API docs don't give you a sense of the struct layout, so really you need to look at both.

(I'm finding the Params stuff to be awkward to use, especially with Gets. I think a better general pattern for client APIs is to follow the standard library's pattern in net/http where you have a type per request and set properties on it, making the request via a Do call. Ie:

req, _ := http.NewRequest("GET", "http://google.com", nil)
req.Header.Set("User-Agent", "awesomesauce")
res, err := http.DefaultClient.Do(req)

For something like getting subscriptions you could add required properties to the request constructor, like:

sub, err := stripe.GetSubscription("sub_4pcfEeZMjXZlGY", "cus_4qlHv0B8e3WVoJ").Do()

Of course, I acknowledge this is all a matter of personal taste.)

PaymentSource truncates all values on the Source when Marshalled

Hi,

Currently we currently proxy requests to Stripe (for example, if the web application need to access the logged in customers' Customer object it hits our API, which hits Stripe).

Unfortunately, when the Customer object is marshalled, it loses all Source information, which is somewhat unexpected.

Perhaps PaymentSource can be transformed into an interface with Type(),ID(),Card() and BitcoinReciever() methods, and have Card or BitcoinReciever implement these methods? (Not backwards compat?)

Or maybe add a custom MarshalJson function that makes sure PaymentSource marshals itself appropriately?

SubParams: Support trial_end: now

The sub params do not support the special now value for TrialEnd. Using time.Now().Unix() is problematic because depending on server/network lag you could end up with the following error

Error encountered from Stripe: {"type":"invalid_request_error","message":"Invalid timestamp: must be an integer Unix timestamp in the future.","param":"trial_end"}

I think a EndTrial bool would work nice for this case.

https://stripe.com/docs/api/go#update_subscription

Iterator conventions

Congrats on releasing this package! It looks comprehensive and clean. I have one initial suggestion, if you're interested:

I find the naming convention and behavior for iterators in this package a little confusing. In particular, does the Next method produce a new value every time it is called, or does it simply access a single stored item between calls to Stop? For example, does the following code print one value twice, or two different values?

i := plan.List(params)
for !i.Stop() {
    log.Println(i.Next())
    log.Println(i.Next())
}

It is not clear. (Even after reading the documentation it remains unclear, since the comment there says essentially nothing beyond repeating the name of the method.)

In contrast, two standard library types (bufio.Scanner and sql.Rows) have adopted a slightly different convention: the driver method that goes in the for loop condition is called Next or Step rather than Stop, and, importantly, the iterator provides accessor methods for the current item in the sequence.

Using the standard library convention, the documented example for plan.List would look like this:

stripe.Key = "sk_key"

params := &stripe.PlanListParams{}
params.Filters.AddFilter("limit", "", "3")
params.Single = true

i := plan.List(params)
for i.Next() {
    plan, err := i.Plan()
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("%v ", plan.Name)
}

and my example above would look like either this:

i := plan.List(params)
for i.Next() {
    log.Println(i.Plan())
    log.Println(i.Plan())
}

or this, depending on the meaning of the API as it currently stands:

i := plan.List(params)
for i.Next() {
    log.Println(i.Plan())
    i.Next()
    log.Println(i.Plan())
}

Either way, it is self-evident.

I suggest that Stripe should consider adopting the standard library's convention, both for the sake of consistency and because it is (IMO) inherently less confusing.

You could go further, and put the error in a separate accessor method (as done by Scanner) but that's a separate issue.

gofmt issue

Seems that the github.com/stripe/stripe-go/customer.go file got committed without go fmt being run.

@@ -18,7 +18,7 @@

 // SetSource adds valid sources to a CustomerParams object,
 // returning an error for unsupported sources.
-func (cp *CustomerParams) SetSource(sp interface{}) (error) {
+func (cp *CustomerParams) SetSource(sp interface{}) error {
        source, err := SourceParamsFor(sp)
        cp.Source = source
        return err

Event user_id not included in Event struct

I'm working on a 3rd party stripe app. I saw in the webhook docs that a user_id property will be returned if your using Stripe Connect so you can identify the stripe user the even belongs to.

While developing I was not getting the user_id in the Event instance. I noticed that the Event struct does not include that UserId property event.go#L7, so that JSON field is never decoded.

I made a quick change to event.go to see if I could fix it, and everything was working as expected:

type Event struct {
    ID       string     `json:"id"`
    Live     bool       `json:"livemode"`
    Created  int64      `json:"created"`
    Data     *EventData `json:"data"`
    Webhooks uint64     `json:"pending_webhooks"`
    Type     string     `json:"type"`
    Req      string     `json:"request"`
    UserId   string     `json:"user_id"` // The new line
}

If I created a PR to fix this, would it get merged?

Stripe Connect Support

Is it possible to use Stripe Connect with this API? If so, can you provide some examples?
Thanks!

Customer Email and Desc params aren't loaded

I can load a customer via customer.Get(customerId) directly and see the Email and Desc correctly.

However, if I load all charges for that same customer using charge.List(), and then try to access charge.Customer.Desc and charge.Customer.Email, they are both always blank.

I was expecting charge.Customer to display all attributes from the Customer struct.

In the ruby client, I'm able to pass expand: ['data.customer'] to load the details of the customer. However, I don't see how to do so using ChargeListParams or ListParams.

`token` is a confusing name for the API key.

Several places in the code use token as a field name or method parameter to refer to a Stripe API key. Given that "token" is already heavily overloaded in Stripe-land, I think it's more confusing than e.g. apiKey.

EventData should make raw JSON for Obj available

The data contained in the Obj field is always (?) a valid Stripe object, and the various objects support JSON unmarshaling. I'd like a json.RawMessage field in the EventData for the object so I could unmarshal it to a real object rather than having to use a map[string]interface{}. This is what I do with my code currently:

type webhookEvent struct {
    ID   string `json:"id"`
    Type string `json:"type"`
    Data struct {
        Object             json.RawMessage        `json:"object"`
        PreviousAttributes map[string]interface{} `json:"previous_attributes"`
    } `json:"data"`
}

func invoiceCreatedHandler(ev *webhookEvent) error {
    var invoice stripe.Invoice

    if err := json.Unmarshal(ev.Data.Object, &invoice); err != nil {
        return err
    }
}

http client usage on appengine

I am not sure how setting http client globally works under app engine, where it is unique per request. Does the request attach to the correct context with concurrent access to the API.

I saw it is handled with passing a context in go oauth2 client.
please see here.
https://github.com/golang/oauth2/blob/master/client_appengine.go
https://github.com/golang/oauth2/blob/master/oauth2.go#L160

This may be evasive as all function needs to take a context as argument.

so, currently, am I expect to set the client before all API calls?

Update subscription "TrialEnd"

Hello,

Error encountered from Stripe: {"type":"invalid_request_error","message":"Invalid timestamp: must be an integer Unix timestamp in the future.","param":"trial_end"}

It would be good if Update have new params "TrialEndNow"

Thanks.

Application Fee `Get` method is POST'ing a refund inappropriately

https://github.com/stripe/stripe-go/blob/master/fee/client.go#L35

Hi,

The Get method for Fee's is making a POST call to the refund endpoint, which then refunds the fee instead of returning unmodified fee information. Is this a bug or am I misunderstanding the usecase of Get here?

It seems like there should be both a method to Get the data and one to Refund (which the Get currently does).

Docs: https://stripe.com/docs/api/go#retrieve_application_fee

Thanks for the help!

stripe.com/docs often say "panics an error if..." but code doesn't match up

This sounded strange as it would be pretty non-idiomatic to panic out of a library like this, so I spot-checked a few places[1] and found that the library is doing the right thing and just returning non-nil errors.

Please fix the documentation to not confuse/scare newcomers like me.

[1]
https://stripe.com/docs/api/go#create_customer
vs
https://github.com/stripe/stripe-go/blob/master/customer/client.go#L68

https://stripe.com/docs/api/go#create_card
vs
https://github.com/stripe/stripe-go/blob/master/sub/client.go#L65

Custom Form

How do I build a custom payment form without requiring my customers to use their card details?

List total_count must be array

The documentation states that you can use params.Filters.AddFilter("include", "", "total_count") to fill out metadata, but the include type is forced to be an array.

Documentation should say: params.Filters.AddFilter("include[]", "", "total_count")

No examples in GoDoc

Right now there are no examples in GoDoc. We should have a list, create, update, and delete example.

Adopt style guidelines for naming (Id -> ID), run golint over tree

golint (https://github.com/golang/lint) is a handy tool for ensuring that your code conforms to stylistic best practices, especially when it comes to naming. The guidelines are here: https://code.google.com/p/go-wiki/wiki/CodeReviewComments

In particular, things like Id, Api, Url, and Http should be ID, API, URL, and HTTP to match the standard library's conventions. It's frustrating when my own code uses ID but stripe's uses Id -- it results in a lot of compile-time errors.

Other than that, stripe-go is pretty golint-clean. There are a few complaints about lack of comments on exported identifiers, but nothing too severe.

[docs] Clarify error/result of charge.New()

It looks like the error returned from a new charge is specifically HTTP and other language-level errors, not things like invalid number, card declined. Am I understanding this correctly?

I'd be happy to update the docs, I just wanted to check with you first that my understanding is correct.

Mismatch between API docs and golang CLI implementation

According to the API docs, the customer resource responds with a field default_source which is a string representing the ID of the payment source: https://stripe.com/docs/api#create_customer

The Customer type has a field DefaultSource which is a pointer to a PaymentSource: https://github.com/stripe/stripe-go/blob/master/customer.go#L43

It doesn't seem like the code would be able to unmarshal a string into an actual payment source. Am I missing a step?

Some classes of failed transfers have a `nil` error object

Say you are trying to transfer money to a recipient, but your account doesn't have enough funds, and your code looks like:

    params := stripe.TransferParams{
        Amount:    int64(32),
        Currency:  "usd",
        Recipient: user.RecipientId,
        Desc:      "test account payout",
    }
    t, err := sc.Transfers.New(&params)
    if err != nil {
        user.TxfrId = t.Id           
        user.Save()
        return emailConfirmation(user.Email, "Your money will be arriving soon")
     }

In this case you've now told the user their money was paid out, when in fact no money was transferred. Instead you need the following error logic:

func transferError(t *stripe.Transfer, err error) error {
    if err != nil {
        return err
    }
    if t.FailCode != "" {
        return fmt.Errorf("transfer_failure: Transfer %s failed with code %s", t.ID, t.FailCode)
    }
    return nil
}

This was not obvious, and almost led to people not getting paid.

I understand that this is more of an API decision than a library decision, but there's no page for "general questions about API design", and it's particularly an issue in Go when the a) the error return parameter is used everywhere to report errors, and b) most people would categorize "the money will not be transferred" as an error.

Appengine support

Although allowing the http client to be injected does indeed help with appengine usage line 68 of stripe.go is using an explicit Timeout in the http.Client struct literal. Appengine does not allow this. for now I'll be forking this but try using the Transport's deadline instead of the http.Client struct literal's timeout

App Engine: "Call error 3: invalid security ticket"

The documented approach for using this package on App Engine works for the first HTTP request, but never again. Specifically, the documentation says to call

stripe.SetHTTPClient(urlfetch.Client(appengine.NewContext(r)))

That creates and uses an HTTP client which is only valid for the life of the current HTTP request (r). On the next request, one calls stripe.SetHTTPClient again. That sets the default HTTP client but doesn't change the API backend, which still references the HTTP client from the first request.

A second HTTP request might call something like customer.New(...) which calls stripe.GetBackend(stripe.APIBackend) which returns a backend referring to an HTTP client from the first request. Using that HTTP client gives an error like:

Post https://api.stripe.com/v1/customers: Call error 3: invalid security ticket: 6e2752a700a25c35

A better incantation for App Engine is something like:

stripe.SetBackend(stripe.APIBackend, nil)
stripe.SetHTTPClient(urlfetch.Client(appengine.NewContext(r)))

I'd submit a pull request, but I'm not sure if this should be corrected in the documentation, in SetHTTPClient or in GetBackend

Somewhat related, using a global HTTP client in App Engine is bound to cause trouble when simultaneous requests want to call Stripe APIs. Both goroutines will contend over stripe.httpClient and at most one goroutine can win. I wish I could recommend a good solution to that problem.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.