#goodrx-card-enums

1 messages · Page 1 of 1 (latest)

tough pollenBOT
subtle apex
#

goodrx-card-enums

crystal crypt
#

Thank you @subtle apex for looking into this. Yes I'm aware that these are different object classes and it may not be unreasonable to have different enum values due to implementation detail reasons. I'm not trying to argue that. The issue I have, is though, with the decision that the enum values for the same card brand concept are different, the returned object to stripe event webhook is a plain string, as the links of the documentation you provided showed. I also verified in stripe-python source code that the corresponding object class does not provide enum to simplify client side integration. aka I'd have to look into each and every event that may contain card brand just to figure out if there're different brand values.

subtle apex
#

stripe-python has no enums or any types really yes.

crystal crypt
#

to me that's not very efficient, and I was raising the question to see if there's a possibility to expose possible values as typed enum, or if there's a stipe util to consolidate those, or make those enum consistent

subtle apex
#

Sorry I don't really get the question. IF you get different Events with completely different objects, you'll get completely different behaviour, tht's normal

#

And making them consistnet wouldn't really make sense either

crystal crypt
#

the way that returned payload from stripe webhook makes it impossible to parse below object, the values were returned as plain string

#

developers won't know what are the possible values without looking into each and every implementation of card brand

#

And making them consistnet wouldn't really make sense either

with all due respect, I disagree with the evaluation. IMHO for the same business concept, it makes a lot of sense to have enum values consistent

subtle apex
#

Let's take this one step at a time as I think you have multiple completely separate questions here and I'm really confused by what you're asking

#

First: type of objects and Events. As a developer, with a recent enough integration, you should basically never care about or listen to the event customer.source.*. They are old and for old APIs, they were re-designed/replaced in 2018 and are here for compatibility reasons.

There are legit situations where you need those but they are really rare. So let's start with this topic. Why are you looking at those Events?

crystal crypt
#

we use event webhook so we don't have to flood stripe APIs? I'm not sure the reason of why we need to look into the events matter to the enum values TBH.

subtle apex
#

Let's try my way. Just for context, I'm a developer, I've been at Stripe for many years and I know our APIs inside out (and helped design a lot of those)

#

I'm not asking why you use Events or listen to webhooks. I'm asking why you/your code listens to a specific type of Events the ones that are customer.source.*

crystal crypt
subtle apex
#

you said those words. Which is your code explicitly looking at that specific Event type. This was deprecated years ago and is here mostly for compatibility reasons. So I'm trying to figure out why you look at it so that I can help you find a better path

crystal crypt
subtle apex
#

let's ignore that

#

Sorry, I'm really trying to help you, just try to explain to me why you do

#

Is it mostly: you listen to all Events today and try to deal with them as they come? If so I can help>

#

Or is it another reason and if so what is that reason

crystal crypt
#

you listen to all Events today and try to deal with them as they come?
this is the use case. I'm all ears on what's your recommendation to replace these.

subtle apex
#

Okay, so really my advice is to never do that.

#

Most integrations only need a really small subset of Events and you should configure your webhook endpoint to only listen to those specific events

#

So for example you should not listen to customer.source.* and so you would never receive it or have to deal with it

crystal crypt
#

???

#

we have business reasons that we need the event

subtle apex
#

You just said the opposite, that you listen to all Events

#

What is your business reason then?

crystal crypt
#

> You just said the opposite, that you listen to all Events is not mutual exlusive to the fact that we use the event for business reason

#

the fact that we parse events doesnt mean we don't use it

#

one event processing action we do is to update customer payment methods on the "customer.source.updated" event

subtle apex
#

Cool so you do have a reason to listen to that Event, which is exactly what I was asking earlier. Can you give me an example Event id evt_123 of that type so that I can show you something concrete with it?

crystal crypt
#

I'm confused, I stated that we are parsing the event and we are processing card brand values from either "customer.source.updated" or "charge.succeeded". you said that you know the APIs inside out, and you confirmed that the enum values are different. I'm not sure what else should I provide

#

the related data is the card brand

#

which is documented, you confirmed

subtle apex
#

Can you give me an example Event id so that I can show you?

crystal crypt
subtle apex
#

That's a charge.succeeded Event so it's a completely different Event.

crystal crypt
#

another one is "id": "evt_1NO12tHMtOGkm4dBGNp32Zdl",

crystal crypt
subtle apex
#

I am trying to help you understand why you shouldn't need to listen to customer.source.* Events. So I'm only asking you for Events of that type.

crystal crypt
#

Yup thanks for clarifying your request. I shared 2 event ids, 1 for each. You can see the brand coming from 2 different set of values

subtle apex
#

Okay so look at https://dashboard.stripe.com/events/evt_1NO12tHMtOGkm4dBrFVVEpCz
This is a different Event of type payment_method.card_automatically_updated for the same object. That Event and the other one describe the same exact change to the underlying card just through 2 completely different APIs.
One is the legacy Card API and the newer one is the PaymentMethod API from 2018. Because that object you have was created originally with the legacy API, we have to generate both Events since we don't know which one you want.

But if your webhook endpoint listens to payment_method.card_automatically_updated and not customer.source.updated you will get the exact information you want already with the newer API

#

It seems like right now your have a webhook endpoint on your Stripe account that already listens to a subset of events and you are listening to customer.source.updated explicitly and not listening to payment_method.card_automatically_updated for example (or payment_method.automatically_updated which is the even newer one)

#

So as far as I can tell right now you never deal with payment_method.* Events so you shouldn't have to care about that discrepancy right?
The problem is that you look at an old object (The Card API resource) built in 2012 or so and you also look at charge.succeeded about the Charge object. At the time years ago the Charge object expanded the entire Card object in the API. Later we improved this by adding payment_method_details which is a snapshost of the payment method information at the time of Charge creation. This was done in 2018 when we shipped the newer more generic PaymentMethod API (That works for card and many other payment methods)
At the time we had to pick one of the two enum lists for card brands. We picked the cleaner/newer one from PaymentMethod.
It is different from Card but those are for older integrations. We could have changed those too but it'd have required an API version and confused a lot of existing integrations who wouldn't have wanted to migrate those values

crystal crypt
#

Thanks for sharing the context. So my takeaway is that we need to configure the event webhook and update integration to parse new event types for slightly different data with newer version enum values on card brands

#

they were re-designed/replaced in 2018 and are here for compatibility reasons.

We could have changed those too but it'd have required an API version and confused a lot of existing integrations who wouldn't have wanted to migrate those values

FWIW, what you described here doesn't sound like a right solution for compatibile changes

subtle apex
#

I'm happy to debate that for sure if you're interested. I disagree, what we did works really well. It has some downsides like the one you experience (but it usually comes from listening to the wrong Events) but it is a lot better than if we had forced every integrations on older APIs to use the newer enums

#

for example you're on a 2020 API version (so 2 years after those changes) and you still use the old Events/APIs

crystal crypt
#

One recommendation, if stripe api developers decided to consider certain events deprecated, at least mark it so on documentation website, and link to the new event type

#

I'm not interested in debating it because I happen to be also experienced in public API designs

subtle apex
#

for the deprecated part I agree personally but when we have tried that, lots of existing developers get super worried about their integration being broken or removed soon. It's... tough

#

What's important to understand is that they all work fine and have for years and you pick and choose what you want based on your needs and use-case.
Earlier on you started with listening to Events that are conceptually duplicative and having different enums so that's what I wanted to get to the root of at least and hopefully I did that

crystal crypt
#

Yup. thanks again for sharing the context. Only wanted a solution. Thanks for working this out

subtle apex
#

Now the second part of your question that confused me was around everything being a string. Even with stripe-python when you receive an Event you would usually go and deserialize the underlying object. So when you get charge.succeeded you get a Charge object and when you get customer.created you get a `Customer object

#

code like this ```if event and event['type'] == 'payment_intent.succeeded':
payment_intent = event['data']['object'] # contains a stripe.PaymentIntent
print('Payment for {} succeeded'.format(payment_intent['amount']))

Then define and call a method to handle the successful payment intent.

handle_payment_intent_succeeded(payment_intent)

elif event['type'] == 'payment_method.attached':
payment_method = event['data']['object'] # contains a stripe.PaymentMethod

Then define and call a method to handle the successful attachment of a PaymentMethod.

handle_payment_method_attached(payment_method)```

tough pollenBOT
subtle apex
#

The last thing is: stripe-python doesn't have "enums" yet. It's definitely a big shortcoming that we want to fix one day. The problem is that to have enums and types you need to "pin" to a specific API version and that is a pretty big lift for most integrations when today you can use the latest version of stripe-python with any API version and it "just works". But at the cost of you having to maintain those "types" yourself 😦

crystal crypt
#

I don't want a debate. Just to continue the conversation on stripe python API typing.

i'm curious what's the remaining processing source code of the example you shared. if you had a chance to look into stripe-python source code, the Card class implementation looks like this:


class Card(DeletableAPIResource, UpdateableAPIResource):
    OBJECT_NAME = "card"

    def instance_url(self):
      ...

    @classmethod
    def modify(cls, sid, **params):
    ...

    @classmethod
    def retrieve(
        cls,
        id,
        api_key=None,
        stripe_version=None,
        stripe_account=None,
        **params
    ):
        
#

stripe-python doesn't have "enums" yet
yep that's what I was trying to say

#

But at the cost of you having to maintain those "types" yourself
thanks for confirming this.