linkedin-developers / linkedin-api-js-client

LinkedIn API JavaScript Client Library
Other
75 stars 16 forks source link

Getting "Method 'GET' is not supported for URI" when trying to retrieve an email address #14

Closed avidan-chen closed 1 year ago

avidan-chen commented 1 year ago

Getting the following error when trying to retrieve the user's email address:

"Method 'GET' is not supported for URI '/clientAwareMemberHandles?viewer=urn%3Ali%3Amember%3A11580475&q=members&members=List(urn%3Ali%3Amember%3A11580475)&onlyPrimary=true&type=EMAIL&fields=handle"

My code looks like this:

const emailResponse = await restliClient.get({
    resourcePath: "/emailAddress",
    queryParams: {
      q: "members",
      projection: "(elements*(handle~))",
    },
    accessToken,
  });

Any help would be appreciated.

avidan-chen commented 1 year ago

Note that this works fine:

const emailResponse = await axios.get(
    "https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))",
    {
      headers: {
        Accept: "application/json",
        Authorization: `Bearer ${accessToken}`,
      },
    },
  );
shimizust commented 1 year ago

Hi @avidan-chen, thanks for trying the client out. The confusion is that while the underlying HTTP method is a GET, LinkedIn's APIs are built on top of Rest.li, which defines more granular methods.

In this case, the call to /clientAwareMemberHandles is a Rest.li FINDER call (you are finding member handles by some search criteria). Here is a working call:

let response = await restliClient.finder({
    resourcePath: '/clientAwareMemberHandles',
    finderName: 'members',
    queryParams: {
      projection: "(elements*(primary,type,handle~))"
    },
    accessToken
  });
  console.log(response.data.elements);

Response:

[
  {
    handle: 'urn:li:emailAddress:...',
    type: 'EMAIL',
    'handle~': { emailAddress: 's...@...com' },
    primary: true
  }
]

In this case, the finderName is "members". Finder name is a required parameter for a finder request, so it is explicitly listed as a separate input parameter. It will be added to the query parameters, though.

Hope that helps!

avidan-chen commented 1 year ago

@shimizust thanks for the reply. I am not familiar with Rest.li, however I am very much familiar with REST API semantics and I have to say this is very counter intuitive.

Looking at the examples in this page: https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin

It seems that similar to the me resourcePath, emailAddress should also be a resourcePath, and that q=members should be a query param.

I'm not sure I understand the strange syntax that goes on here, but I bet it would be much easier for me & other developers if you would expose all the functionality as Typescript functions (for example, getEmailAddress() or getLiteProfile with proper types and hide all those Rest.li semantics. I think this would make adopting this library much easier.

shimizust commented 1 year ago

Hi @avidan-chen , I definitely agree that an easier API would be higher-level (e.g. getEmailAddress() or getLiteProfile(), as you said). Unfortunately, for various reasons, it is not feasible at the moment to broadly generate or maintain this type of high-level client library.

Thus, an intermediate solution is to provide a library that operates at the Rest.li level and abstracts away some of the complexity of working with LinkedIn's Rest.li APIs. Partners can more easily build their own data services on top of this library, or our internal business units can use this to build higher-level client libraries for their API products.

A big issue is easily translating our API docs to client requests. Many docs don't make it very clear which Rest.li method is being used and only provide the raw HTTP request parameters. If that were made clearer, it becomes more trivial to create the client request. I will pass this feedback on to our techwriting team.