Calling Third party REST API with Skuid

  • 2
  • Question
  • Updated 3 years ago
  • Answered
I am trying to call this third party REST API with Skuid and running into some issues. When I click the URL from the Configure -> Model Services -> "URL / Domain" link, I get an <status>ok</status> page. I am guessing that means its all good.

However, I am then stuck trying to figure out how to make calls from my Model for this. Here is how I configured my model services...



Per the docs, I need to send the credentials in the header, and then use the Authentication token with my subsequent requests.
https://docs.dnb.com/direct/2.0/en-US/authentication/latest/rest-API



Can someone please help. I am a newbie with Skuid, and am still trying to understand how I can use Skuid to access these third party REST APIs.

Thanks!
Photo of DS

DS

  • 110 Points 100 badge 2x thumb

Posted 3 years ago

  • 2
Photo of Skuidward Tentacles (Raymond)

Skuidward Tentacles (Raymond), Champion

  • 17,224 Points 10k badge 2x thumb
You may want to check out this thread. Ultimately the problem I had was due to a limitation in Skuid that they are going to try to remedy in the next build.
https://community.skuidify.com/skuid/...
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
For connecting to Dunn and Bradstreet, this configuration should work:



We highly recommend entering your Username and Password under  "Authentication Details" so that they will be protected --- you can merge in the Username and Password values into the x-dnb-user and x-dnb-pwd headers using {{$Auth.Username}} and {{$Auth.Password}}, respectively. If you do this, the Username and Password are injected server-side into the authentication HTTP Request, such that it is impossible for a user making use of this Model Service to know what the Username and Password were. If you do it the way you currently are, then a user would be able to use the JavaScript Console to inspect the AJAX requests that Skuid makes to the server and determine what username / password were transmitted to DNB to obtain an Authorization token.

The only other piece that you're missing is Common Request Headers --- expand the section entitled "Headers to send with every request" and this will bring up an editor allowing you to define headers that will be transmitted with every non-authentication request to this Model Service. For DNB, you need to send an Authorizationheader with every request, containing the value of the "Authorization" parameter returned in the Authentication response body. To obtain this value, you need to use the merge: {{$Auth.Response.Headers.Authorization}}. (NOTE: technically you need to be getting {{$Auth.Response.Body.Authorization}} , but there is a bug with the current release of Skuid that is not incorrectly switching the Auth Response Body with Auth Response Headers, and there is no current way to access the Auth Response Body. This will be corrected as of Skuid Banzai Update 7).
Photo of DS

DS

  • 110 Points 100 badge 2x thumb
Thanks Zach and Raymond. I was able to set it up, and I appreciate such helpful response.

However, when I create a model, I don't see the field names. DnB's JSON response seems to have these defined so I am a little unsure if this is something that I am not setting up correctly my end or what.




Also, I tried setting up the search so that a user can lookup an account name via the DnB web service...but it looks like that is not working either. Here is the response I get on the UI



And, here is how my UI config looks like..



Am I missing something? Appreciate the help. Looks like Skuid can really help us get rid of a lot of Apex callouts :)
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
What Service URL are you connecting to? 
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Try using V5.0 , and have your Service URL be relative to your Model Service's base URL, e.g. /V5.0/organizations. See the example page XML I posted below for a working starting point. 

One of the key concepts for working with REST Models is Path to Contents, which is very important to understand when you are trying to display Tables on Models with multiple rows. Very often, your REST service will return an object as its response, and buried somewhere within this object is an Array of rows that you want to use as the "contents" of your Model. However, you need to tell Skuid where to find this Array. This is the purpose of the Path to Contents property on the Model. For the DNB example here, you need to click on Path to Contents, then click the arrow next to "MatchResponse" , then click the arrow next to "MatchReesponseDetail", and then click the RADIO BUTTON next to "MatchCandidate". Notice that MatchCandidate is an ARRAY. This contains the array/list of DNB records that match your search criteria.
Photo of DS

DS

  • 110 Points 100 badge 2x thumb
Here is the XML of the page
<code>
  <skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="true" showheader="true"> <models> <model id="DnBSource" limit="20" query="false" createrowifnonefound="false" adapter="REST" processonclient="true" service="DnB3" type="" label="Match" labelplural="Matches" verb="GET" endpoint="https://maxcvservices.dnb.com/V2.0/organizations?match"> <fields> <field id="0" label="0" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="1" label="1" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="2" label="2" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="3" label="3" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="4" label="4" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="5" label="5" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="8" label="8" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="9" label="9" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="10" label="10" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="11" label="11" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="12" label="12" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="13" label="13" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="14" label="14" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="15" label="15" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="16" label="16" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="17" label="17" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="18" label="18" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="6" label="6" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> <field id="7" label="7" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/> </fields> <conditions/> <actions/> </model> </models> <components> <grid uniqueid="sk-2d_xJC-128"> <divisions> <division behavior="flex" minwidth="100px" ratio="1"> <components> <skootable showconditions="true" showsavecancel="false" showerrorsinline="true" searchmethod="client" searchbox="true" showexportbuttons="false" pagesize="10" createrecords="false" model="DnBSource" buttonposition="" mode="readonly" uniqueid="sk-2e0HD0-263" emptysearchbehavior="query" instantfilters="false"> <fields> <field id="0"/> <field id="1"/> <field id="2"/> <field id="3"/> <field id="4"/> <field id="5"/> <field id="6"/> <field id="7"/> </fields> <rowactions/> <massactions usefirstitemasdefault="true"/> <views> <view type="standard"/> </views> <renderconditions logictype="and"/> <searchfields/> </skootable> </components> </division> </divisions> <styles> <styleitem type="background" bgtype="none"/> </styles> </grid> </components> <resources> <labels/> <javascript/> <css/> </resources> <styles> <styleitem type="background" bgtype="none"/> </styles> </skuidpage> <br>
(Edited)
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Here is the XML for a working page example using the /V5.0/Organizations endpoint:

<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="false" showheader="true" tabtooverride="Account">   
   <models>
      <model id="DNBOrganizations" query="true" createrowifnonefound="false" adapter="REST" processonclient="true" service="DnB3" type="" verb="GET" endpoint="/V5.0/organizations?CountryISOAlpha2Code=US{{#subjectName}}&amp;SubjectName={{subjectName}}{{/subjectName}}&amp;match=true&amp;MatchTypeText=Advanced" pathtocontent="MatchResponse.MatchResponseDetail.MatchCandidate">
         <fields>
            <field id="OrganizationPrimaryName.OrganizationName.$" label="Company Name" ispolymorphic="false" isnamepointing="false" displaytype="TEXT" accessible="true" filterable="true"/>
            <field id="TelephoneNumber.TelecommunicationNumber" label="Phone Number" ispolymorphic="false" isnamepointing="false" displaytype="TEXT" precision="10" scale="0" accessible="true" filterable="true"/>
            <field id="OperatingStatusText.$" label="Operating Status" ispolymorphic="false" isnamepointing="false" displaytype="TEXT" accessible="true" filterable="true"/>
            <field id="OrganizationIdentificationNumberDetail.@DNBCodeTableNumber" label="@DNBCodeTableNumber" ispolymorphic="false" isnamepointing="false" displaytype="DOUBLE" precision="1" scale="0" accessible="true" filterable="true"/>
            <field id="OrganizationIdentificationNumberDetail.@DNBCodeValue" label="@DNBCodeValue" ispolymorphic="false" isnamepointing="false" displaytype="DOUBLE" precision="5" scale="0" accessible="true" filterable="true"/>
            <field id="OrganizationIdentificationNumberDetail.@TypeText" label="@TypeText" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/>
            <field id="OrganizationIdentificationNumberDetail.OrganizationIdentificationNumber" label="Org Identifier #" ispolymorphic="false" isnamepointing="false" displaytype="TEXT" accessible="true" filterable="true"/>
            <field id="PrimaryAddress.PrimaryTownName" label="City" ispolymorphic="false" isnamepointing="false" displaytype="TEXT" accessible="true" filterable="true"/>
            <field id="PrimaryAddress.CountryISOAlpha2Code" label="Country Code" ispolymorphic="false" isnamepointing="false" displaytype="TEXT" accessible="true" filterable="true"/>
            <field id="PrimaryAddress.PostalCode" label="Zip Code" ispolymorphic="false" isnamepointing="false" displaytype="TEXT" accessible="true" filterable="true"/>
            <field id="PrimaryAddress.StreetAddressLine" label="Street Address" ispolymorphic="false" isnamepointing="false" displaytype="ARRAY" rel="StreetAddressLine" ref="StreetAddressLine" referenceto="[object Object]" accessible="true" filterable="true"/>
            <field id="PrimaryAddress.StreetAddressLine.LineText" label="LineText" ispolymorphic="false" isnamepointing="false" displaytype="STRING" accessible="true" filterable="true"/>
            <field id="DUNSNumber" label="DUNS Number" ispolymorphic="false" isnamepointing="false" displaytype="TEXT" precision="10" scale="0" accessible="true" filterable="true"/>
            <field id="MatchQualityInformation.ConfidenceCodeValue" label="Confidence Value" ispolymorphic="false" isnamepointing="false" displaytype="DOUBLE" precision="2" scale="0" accessible="true" filterable="true"/>
         </fields>
         <conditions>
            <condition type="fieldvalue" value="" enclosevalueinquotes="true" sourcetype="param" sourceparam="subjectName" state="filterableoff" inactive="true" name="subjectName"/>
         </conditions>
         <actions/>
      </model>
   </models>
   <components>
      <skootable showconditions="true" showsavecancel="false" showerrorsinline="true" searchmethod="server" searchbox="true" showexportbuttons="false" pagesize="10" createrecords="false" model="DNBOrganizations" buttonposition="" mode="readonly" uniqueid="sk-2eMJrr-143" emptysearchbehavior="query" searchconditionname="subjectName" searchplaceholdertext="Enter a company name...">
         <fields>
            <field id="OrganizationPrimaryName.OrganizationName.$"/>
            <field id="OrganizationIdentificationNumberDetail.OrganizationIdentificationNumber" valuehalign="" type=""/>
            <field id="DUNSNumber" decimalplaces="" valuehalign="" type=""/>
            <field id="MatchQualityInformation.ConfidenceCodeValue" decimalplaces="" valuehalign="" type=""/>
            <field id="OperatingStatusText.$" valuehalign="" type=""/>
            <field id="PrimaryAddress.StreetAddressLine" valuehalign="" delimiter="&lt;br/&gt;">
               <label>Street Address</label>
               <template>{{LineText}}</template>
            </field>
            <field id="PrimaryAddress.PrimaryTownName"/>
            <field id="PrimaryAddress.CountryISOAlpha2Code"/>
            <field id="PrimaryAddress.PostalCode"/>
            <field id="TelephoneNumber.TelecommunicationNumber"/>
         </fields>
         <rowactions/>
         <massactions usefirstitemasdefault="true"/>
         <views>
            <view type="standard"/>
         </views>
      </skootable>
   </components>
   <resources>
      <labels/>
      <css/>
      <javascript/>
   </resources>
   <styles>
      <styleitem type="background" bgtype="none"/>
   </styles>
</skuidpage>
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Which produces a basic table looking like this, with the Table defining a Search Condition mapping to a Condition on the Model so that you can search for company names. In the DNB Sandbox, there's only ever one result that gets returned, but this should work in a real environment as well.

(Edited)