customerio / customerio-ruby

A ruby client for the Customer.io event API.
https://customer.io/docs/api/
MIT License
64 stars 75 forks source link

[Feature Request] Add support for deduplicating events with event IDs #107

Open marckohlbrugge opened 10 months ago

marckohlbrugge commented 10 months ago

From the documentation

From https://customer.io/docs/journeys/events/#deduplicating-events

You can provide an id with your events, to deduplicate events—if there’s a possibility that your integration might send duplicate events. The id must be a ULID. If two events contain the same id, we won’t process the event multiple times.

Deduplicating events helps you accurately represent people’s activity; can prevent people from accidentally entering or leaving campaigns based on the number of times that a person performed an event; and prevents duplicate events from impacting your workspace’s performance.

{
    "name": "my event",
    "id": "01BX5ZZKBKACTAV9WEVGEMMVRY",
    "data": {
        "prop1": "value"
    }
}

Relevant code

https://github.com/customerio/customerio-ruby/blob/f9984a713950d79e1586b84930a55990aeebb3c0/lib/customerio/client.rb#L160-L166

https://github.com/customerio/customerio-ruby/blob/f9984a713950d79e1586b84930a55990aeebb3c0/lib/customerio/client.rb#L186-L193

https://github.com/customerio/customerio-ruby/blob/f9984a713950d79e1586b84930a55990aeebb3c0/lib/customerio/client.rb#L47-L52

Problem

As you can see, the expected JSON has a top-level id attribute. However, the existing code doesn't allow for this. Apart from a handful exceptions, it nests all attributes into a data object.

This means users of the gem currently don't have a way to provide an id to prevent duplicate events.

Proposed fix

Add an (optional) id parameter to create_event and all methods that reference it. Pass it as a top-level key to the API.

This will be a backwards-compatible change, as current implementations won't currently provide an id directly into the create_event calls. Notably, any id that might be included in the attributes hash continue to work as before.

def track(customer_id, event_name, attributes = {}) needs to be updated too. This is a bit trickier, because it uses positional arguments. I think adding a fourth, optional argument does the trick: def track(customer_id, event_name, attributes = {}, id = nil)

Optionally, the following code can be used to validate the correctness of the id:

def valid_ulid?(ulid)
  !!(ulid =~ /\A[0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz]{26}\z/)
end