Widget REST API Requests

Hello,

I’m hoping to create a widget that will display data about referenced records from a reference field.

I see a couple of examples of widgets here Swimlane Platform Custom Widgets that appear to lookup reference records and display data about them. For example, the Reference Records Table.

Looking at the code for that widget it looks like there are two ways that the widget is authenticating a request to the Swimlane API to retrieve the record data:

  getReferencedApp() {
    const appId = this.contextData.application.fields.find(f => f.key === referenceFieldKey).targetId;
    return fetch(`${location.origin}/api/app/${appId}`, {
      method: 'GET',
      headers: {
        **Authorization: `Bearer ${this.contextData.token}`,**
        'Content-Type': 'application/json'
      }
    }).then(res => {
      return res.json();
    });
  }

and

  getReferences(fieldIds) {
    if (this.referencedApp && !fieldIds.includes(this.referencedApp.trackingFieldId)) {
      fieldIds = [...fieldIds, this.referencedApp.trackingFieldId];
    }

    const body = {
      fieldIds: fieldIds,
      recordIds: this.record[referenceFieldKey]
    };
    **const token = localStorage.getItem('jwt_token');**
    return fetch(`${location.origin}/api/app/${this.contextData.application.id}/record/${this.record.id}/references`, {
      headers: {
        Authorization: `Bearer ${token}`,
        Accept: 'application/json, text/plain, */*',
        'Content-Type': 'application/json;charset=UTF-8'
      },
      method: 'POST',
      body: JSON.stringify(body)
    }).then(res => {
      return res.json();
    });
  }

I have tried both of these in my widget editor and neither are working. It appears that this.contextData.token has been replaced with "<<deprecated>>" and there isn’t a jwt entry in local storage. It does appear that the jwt is stored in the cookies, but when trying to reference document.cookie in the widget it is returning an empty string for me.

Does anyone know how to properly authenticate to the Swimlane REST API within a widget?

Thank you

According to this stackoverflow cookies marked with ‘HTTPOnly’ cannot be read by JavaScript. I confirmed that the jwt cookie I’m seeing is marked as ‘HTTPOnly’. So the empty cookie string is expected.

I’ve also observed that the web request being made is sending the cookies with it, but I’m still getting a 401 unauthorized response.

Noticed the observable widget included in the SOC solution extends the SwimlaneEnhancedElement class instead of just the SwimlaneElement class. The enhanced class appears to make a this.api object available. I downloaded the @swimlane/swimlane-widgets npm package (which contains the SwimlaneEnhancedElement class) and started going through the code but I wasn’t making much sense of it. However, utilizing the this.api object appears to be making successful API calls.

for example (from the observable widget):

  async apiReady() {
    let api = await this.api;
    let refField = await api.record.getField(THREAT_INTEL_REF_FIELD);
    let TIApp = await refField.targetApp();
    let TIRecords = await refField.cursor.toArray();
    ...
}

I’m hoping there’s some documentation on this package somewhere, or that someone knows how to make requests to the API itself from within the widget.

Hey I am new on the forum!
Thanks for sharing!

For what it’s worth still struggling with this.

Appears the SwimlaneEnhancedElement method I posted above does not update properly when the record’s reference field value is updated.

Turns out you don’t need to supply authentication to the Swimlane API when making a request within a widget. I believe the JWT stored in the cookies I pointed out earlier is supplied with the request.

For example the following code can be supplied as a class method to get an application definition.

  async getApplication(application_id) {
    const response = await 
    fetch(`${this.contextData.origin}/api/${this.contextData.tenantPath}app/${application_id}`);

    if (!response.ok) {
      throw Error(`status: ${response.status}\nurl: ${response.url}\nbody: ${await response.text()}`);
    }