Setup custom IO client with app settings

About

I have the following custom client:

// node/clients/mach.ts
import {
  ExternalClient,
  InstanceOptions,
  IOContext
} from '@vtex/api'

import { Config } from '../config'

export class Mach extends ExternalClient {
  constructor(context: IOContext, options?: InstanceOptions) {
    const headers = options?.headers || {};

    // https://github.com/alefumes/vtexio-dotnet#outbound-requests
    super(Config.mach.baseUrl, context, {
      ...options,
      headers: {
        ...headers,
        'Content-Type': 'text/xml',
        'X-Vtex-Proxy-To': Config.mach.proxyUrl,
      }
    });
  }

  public async addOrder(referenceNumber : string | number, order : any, options: any) {
    // Some business logic not worth sharing
  }
}

As we can see in the constructor of the client, the configuration is currently pulled from the following file:

// node/config.ts
export const Config = {
  mach: {
    securityCode: 'REDACTED',
    baseUrl: 'http://mach.rebellwrap.com/machws',
    proxyUrl: 'https://mach.rebellwrap.com:8183'
  }
}

I’m in the process of switching this hard-coded configuration to settingsSchema – That way, the admin will be able to configure these settings in the admin panel.

After some investigation, I came up with the following:

// manifest.json
// ....
"settingsSchema": {
  "title": "Vtex To Mach",
  "type": "object",
  "properties": {
    "machUrl": {
      "title": "Mach URL",
      "description": "A somewhat good description",
      "type": "string"
    }
  }
}
// ...

and I’ve been able to retrieve the settings in a “test” route:

// node/index.ts

// ...
export default new Service({
  clients,
  routes: {
    run: method({
      GET: async (context: Context) => {
        const response = await context.clients.apps.getAppSettings(process.env.VTEX_APP_ID!)

        context.body = response
        context.status = 200;
        context.set('cache-control', 'no-cache');
      }
    })
  },
  events: {
    orderReadyForHandling
  },
})

Beautiful!


Blocker :fire:

Knowing that to retrieve the app settings:

  • We need the context to be able to call the method getAppSettings
  • The context IOContext in the constructor of the custom client cannot be used to retrieve the app settings:
constructor(context: IOContext, options?: InstanceOptions) {
  const headers = options?.headers || {};

  // https://github.com/alefumes/vtexio-dotnet#outbound-requests
  super(Config.mach.baseUrl, context, {
    ...options,
    headers: {
      ...headers,
      'Content-Type': 'text/xml',
      'X-Vtex-Proxy-To': Config.mach.proxyUrl,
    }
  });
}
  • Await cannot be used in the constructor of a class

What would be the right way to retrieve the settings to be able to configure the custom client?


I took the time to browse the different nodeJS repos of VTEX Apps · GitHub, but couldn’t find any inspiration since all the different custom clients are currently using an hard-coded configuration.

Thanks for any guidance you could provide :slight_smile:

Hello @tyler, if you could provide some guidance with this question it would be much appreciated :slight_smile:

Hey @Jeremie, welcome to VTEX Community!

I’m not really familiar with using app settings in VTEX IO, so I’ll ask someone else to take a look here.

Meanwhile, could you explain how you came to these conditions?

Here’s an answer I got internally, let me know if it helps in any way!

We faced a similar issue with the WordPress app. While there may be a more ideal solution, our approach was to set an empty string as the baseUrl in the constructor, and then access the app settings during the client methods.

We also utilize a wildcard outbound-access policy to allow access to whatever URL the user provides in the app settings. This was necessary because outbound-access rules do not allow partial wildcards (i.e. *. domain.com cannot be used, and there’s no standard pattern for WordPress domains anyway).