Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intercom find by external ID returns the same class with different data structures #612

Open
Startouf opened this issue Nov 18, 2023 · 1 comment

Comments

@Startouf
Copy link

Version info

  • intercom-ruby version: intercom-4.2.1
  • Ruby version: ruby 2.7.2p137

Expected behavior

It is not clear what the intercom.contacts.find# method does relatively to intercom v2 API.

One would expect the method contacts#find to work when using external_ids just like the companies (which work using company_id): intercom.contacts.find(external_id: xxx). When using the library to find a user by its external ID, we're hoping to find a single user. In case of multiple users with the same external ID (is it possible in Intercom ?), the response should either throw an error (multiple matching user error) or return, to avoid confusion, a different class (like Intercom::ContactSearch or ContactList). When looking at the official REST API, the GET User endpoint seems to work only with intercom user IDs, but one could expect the Ruby gem to provide an abstraction to find users by external IDs as well.

I would have rather have a contacts.find_all method when searching for users using the search contact POST so the expected output would be an iterable list.

Is this some weird behavior introduced when migrating from v1 to v2 of the Intercom API ?

Actual behavior

The responses using contacts.find(id: xxx) and contacts.find(external_id: xxx) give two different data structures, yet they are of the same class (see example below in steps to reproduce)

Steps to reproduce

Here is an example where a call to the API returns 10 different users (they all have different external_id, but for some reason the call returns them all), and the response class is Intercom::Contact which is misleading, because it actually contains several users

irb(main):014:0> rez = intercom.contacts.find(external_id: u.id.to_s)
#<Intercom::Contact:0x000055ca48ce1a18
irb(main):015:0> rez.class
=> Intercom::Contact
irb(main):016:0> rez.data.first.class
=> Hash
irb(main):017:0> rez.data.size
=> 10

Here is the same call retuning only one user as mentioned in the documentation

irb(main):018:0> single_rez = intercom.contacts.find(id: "6558e14xxxx")
=> 
#<Intercom::Contact:0x000055ca4d1ef560
irb(main):019:0> single_rez.data
Traceback (most recent call last):
/usr/local/bundle/gems/intercom-4.2.1/lib/intercom/lib/dynamic_accessors_on_method_missing.rb:24:in `define_accessors_or_call': 'data' called on Intercom::Contact but it has not been set an attribute or does not exist as a method (Intercom::AttributeNotSetError)
irb(main):020:0> single_rez.class
=> Intercom::Contact
irb(main):021:0> single_rez.phone
=> nil

Logs

@Startouf Startouf changed the title Intercom find by external ID returns the same class with different interfaces Intercom find by external ID returns the same class with different data structures Nov 18, 2023
@codymoorhouse
Copy link

codymoorhouse commented May 23, 2024

I will just add an additional layer here. As it stands, it does not look like it is currently possible to practically use this gem to find an individual contact based on their external id.

@Startouf raises an interesting point about the different responses, but those responses actually related to the company resource (not the contacts as suggested above).

It looks like this has to do with subtle differences in the parameters needed and this is pretty easy to reproduce...


1. Create a Client

3.2.1 :001 > client = ::Intercom::Client.new(
  token: INTERCOM_TOKEN,
  api_version: "2.11"
)

2. Finding an Individual Company (using company_id)

This returns back a single object. It is using the Retrieve Companies API endpoint which ultimately calls this line of code. But because company_id is an accepted parameter in the request, it seems to only pull back the one record.

3.2.1 :002 > client.companies.find(company_id: 10000)
 => 
#<Intercom::Company:0x00000001076b4538
 @company_id="10000",
 ...,
>

3. Finding an Individual Company (using external_id) (doesn't actually work)

This returns back a single object with the data attribute populate of any company. It is ASLO using the Retrieve Companies API endpoint which ultimately calls this line of code. Since external_id is not an expected parameter in the request, it just pulls back any data.

3.2.1 :003 > client.companies.find(external_id: 10000)
 => 
#<Intercom::Company:0x0000000111d5de98
 ...,
 @data=
  [
    {
      "company_id"=>"8",
      ...,
    },
    {
      "company_id"=>"18",
      ...,
    }
  ]
>

4. Finding an Individual Contact (using external_id) (doesn't actually work)

When trying to run this logic on the Contacts resource, you just get back an error.

3.2.1 :004 > client.contacts.find(external_id: 10000)
<PATH_TO_GEM>/intercom-4.2.1/lib/intercom/request.rb:222:in `raise_application_errors_on_failure': Requested resource is not available in current API version (Intercom::ApiVersionInvalid)

5. Finding an Individual Contact (using contact_id) (doesn't actually work)

Now, perhaps we can pull a single contact using contact_id like we did with Companies in scenario 2. Unfortunately, this actually resembles getting back multiple unrelated Contacts in the data attribute of the model, which actually resembles scenario 3.

3.2.1 :005 > client.contacts.find(contact_id: 10000)
#<Intercom::Contact:0x000000011301b7b0
 ...,
 @data=
  [
    {
      "external_id"=>"167",
      ...,
    },
    {
      "external_id"=>"47",
      ...,
    },
  ]
>

In Summary (TL;DR)

  • It appears there is no actual way to pull an individual contact based on an external id.

    • According to the docs, there is indeed a way to query a single contact form the API, however, it uses a different URI then what this gem can currently support (e.g. contacts/find_by_external_id)
  • There is a mismatch of responses between different and same objects because of shared functionality under the hood

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants