Migrating a Pack to use alternative endpoints

Hello Pack Makers,

Sometimes you build a Pack against a specific endpoint, like https://example.com/api, and launch it. Later on you find out that there are alternative endpoints for users in other countries or industries and you want to accommodate them. Most often these have been European Union endpoints, like https://eu.example.com/api. How can you accommodate these users without breaking your existing ones?

I’ve done some testing and here are some steps that should allow you to migrate your Pack safely to use multiple endpoints.

Collect the endpoint from the user

You’ll need some way for the user to tell you which endpoint to use with their account. This is best done during the authentication process, so they only need to specify it once and it will be used for all future requests. The easiest way to do this is to add requiresEndpointUrl: true to your authentication configuration.

pack.setUserAuthentication({
  type: coda.AuthenticationType.HeaderBearerToken,
  requiresEndpointUrl: true,
});

This will add an additional field to the authentication dialog where the user can enter the endpoint:

image

However this is a bit error-prone, as users might not know which endpoint they need or may mistype it. If there are a fixed set of endpoints you can instead use a postSetup step to prompt the user for the endpoint to use.

pack.setUserAuthentication({
  type: coda.AuthenticationType.HeaderBearerToken,
  postSetup: [{
    type: coda.PostSetupType.SetEndpoint,
    name: "SelectEndpoint",
    description: "Select the endpoint to connect to:",
    getOptions: async function (context) {
      return [
        { display: "example.com", value: "https://example.com" },
        { display: "eu.example.com", value: "https://eu.example.com" },
      ];
    },
  }],
});

image

This function can also generate the list of endpoints dynamically, if there is an endpoint for listing the valid endpoints for a given user.

Use the endpoint in your code

Now that the user has specified their endpoint you need to update your code to use the one they have selected. The endpoint is stored in context.endpoint, but it won’t be populated for accounts created before this change. When reading that value, fall back to the original endpoint if not set.

pack.addFormula({
  // ...
  execute: async function (args, context) {
    // Backfill the endpoint if not specified.
    let endpoint = context.endpoint ?? "https://example.com";
    // ...
});

Then update your fetch() calls to use that endpoint in the URL. Use the utility coda.joinUrl() to safely build the final URL, as it handles missing or multiple forward slashes.

pack.addFormula({
  // ...
  execute: async function (args, context) {
    // Backfill the endpoint if not specified.
    let endpoint = context.endpoint ?? "https://example.com";
    let response = await context.fetcher.fetch({
      method: "GET",
      // Join the URL.
      url: coda.joinUrl(endpoint, "/api/tasks"),
    });
    // ...
  },
});

Release a new version

Release a new version of your Pack to get the new code out there. Existing accounts should continue to work correctly (thanks to the fallback) and new accounts will select which endpoint they want to use.

4 Likes

Thank you @Eric_Koleda

I must say that aside from all the other benefits of Coda, the ability to use packs to facilitate access to APIs is unprecedented and truly under-recognized so far in the general universe of computing users and power-users. It is a game-changing feature that you have really implemented well.

3 Likes