Skip to content

Learn to call an API

One of the primary use cases for a Pack is to integrate with an external API, allowing users to bring in data or functionality not native to Coda. In this tutorial you'll create a formula that converts an amount of money in another currency to US dollars.

Goal

Build a ToUSD formula that uses an external API to convert currency values to US dollars.

Before starting this tutorial, make sure you have completed:

Select the API

When building a Pack around data from an external API, it's usually best to first select the API and examine its capabilities and requirements, as those may have a large influence on the design of your formula.

For this Pack we'll be using the API provided by exchangerate.host, which is free to use and doesn't require any keys or credentials. As shown in their documentation, you can get the latest exchange rates using the following URL:

https://api.exchangerate.host/latest?base=USD

By default this returns the exchange rate for a single Euro, but we can change the starting currency and amount using URL query parameters:

https://api.exchangerate.host/latest?base=CAD&amount=100

The URL returns a JSON response, which includes the conversion rate for all of the currencies it supports:

{
  "success": true,
  "base": "CAD",
  "date": "2022-06-09",
  "rates": {
    "AED": 292.51651,
    "AFN": 7076.688907,
    // ...
    "USD": 79.659392,
  }
}

Here we see that 100 Canadian dollars converts to 79 US dollars (at the time this request was made.) This will provide us the information we need to build our formula.

Design the formula

Looking at the inputs and outputs to the API, we could imagine a formula that takes an amount and currency code as input and returns a converted amount as a number.

ToUSD(100, "CAD") ==> $79.65

Write the code

Now that we've got our API selected and formula designed we're ready to dive into coding.

Add the standard Pack boilerplate, including the import and Pack declaration.

Define a formula called ToUSD which takes an amount and from parameter.

For the result type use Number, with the value hint Currency to get it to render with a dollar sign.

Hard-code the execute function to return zero for now, which we'll replace later with the real value fetched from the API.

import * as coda from "@codahq/packs-sdk";
export const pack = coda.newPack();

pack.addFormula({
  name: "ToUSD",
  description: "Convert a currency to US dollars.",
  parameters: [
    coda.makeParameter({
      type: coda.ParameterType.Number,
      name: "amount",
      description: "The amount to convert."
    }),
    coda.makeParameter({
      type: coda.ParameterType.String,
      name: "from",
      description: "The currency to convert from."
    }),
  ],
  resultType: coda.ValueType.Number,
  codaType: coda.ValueHintType.Currency,
  execute: async function ([amount, from], context) {
    // TODO
    return 0;
  },
});

With the formula scaffold in place, let's focus in on the execute function.

First we'll need to build the URL to send the request to. While it's possible to construct it manually, the utility function coda.withQueryParameters is easier to use and handles all of the encoding and edge cases.

The first parameter to coda.withQueryParameters is the base URL, and the second is a set of key-value pairs to be placed into the query string. This code will return a URL ending with ?base=<from>&amount=<amount>.

execute: async function ([amount, from], context) {
  let baseUrl =
      "https://api.exchangerate.host/latest";
  let url = coda.withQueryParams(baseUrl, {
    base: from,
    amount: amount,
  });
},

To make the request to the API you need to use the fetcher object, which lives within the formula's context. Its fetch method takes a set of key-value pairs that configure the request.

Set the HTTP method to GET and the URL to the one we previously constructed.

Fetcher requests are asynchronous, meaning that fetch only starts the request, but doesn't wait for it to finish. To do that use the await keyword, which tells our code to pause until the API responds.

The response from the API is captured in the response variable, which you'll use later.

execute: async function ([amount, from], context) {
  let baseUrl =
      "https://api.exchangerate.host/latest";
  let url = coda.withQueryParams(baseUrl, {
    base: from,
    amount: amount,
  });
  let response = await context.fetcher.fetch({
    method: "GET",
    url: url
  });
},

The fetcher response includes lots of information about what the API sent back, but in this case we're interested in the body only. When Coda detects that the response is JSON it will automatically parse it for you.

Referring back to the raw API response we saw earlier, the information you need is in the rates sub-object under the key USD. Since the response is already parsed you can "dot" into that value and return it.

execute: async function ([amount, from], context) {
  let baseUrl =
      "https://api.exchangerate.host/latest";
  let url = coda.withQueryParams(baseUrl, {
    base: from,
    amount: amount,
  });
  let response = await context.fetcher.fetch({
    method: "GET",
    url: url
  });
  let json = response.body;
  return json.rates.USD;
},

For security and transparency reasons, Coda requires that all Packs declare which domains they make requests to. Before your Pack will function property you must add that declaration to your code.

The function pack.addNetworkDomain adds a domain to the Pack's declaration. This line can be added anywhere in your code after the boilerplate, but it's usually done at the top of the file.

Your Pack is allowed to access any sub-domains off of this domain, so it's best to select the root domain of the URLs you are making requests to. In this case, use the root domain exchangerate.host instead of narrower API-specific domain of api.exchangerate.host.

import * as coda from "@codahq/packs-sdk";
export const pack = coda.newPack();

pack.addNetworkDomain("exchangerate.host");

pack.addFormula({
  // ...
});


Try it out

Now that the Pack is written, let's see it in action.

Build the Pack and install it in a doc. Add the ToUSD formula to the page and fill in the parameters.

If everything is working correctly you should get back the currency value converted to dollars.

The formula working in a doc.

Bonus points

Try adding autocomplete on the from parameter to provide the user with the list of supported currency codes, and throw an error if they input an invalid one.

View the full code
import * as coda from "@codahq/packs-sdk";
export const pack = coda.newPack();

pack.addNetworkDomain("exchangerate.host");

pack.addFormula({
  name: "ToUSD",
  description: "Convert a currency to US dollars.",
  parameters: [
    coda.makeParameter({
      type: coda.ParameterType.Number,
      name: "amount",
      description: "The amount to convert."
    }),
    coda.makeParameter({
      type: coda.ParameterType.String,
      name: "from",
      description: "The currency to convert from."
    }),
  ],
  resultType: coda.ValueType.Number,
  codaType: coda.ValueHintType.Currency,
  execute: async function ([amount, from], context) {
    let baseUrl =
        "https://api.exchangerate.host/latest";
    let url = coda.withQueryParams(baseUrl, {
      base: from,
      amount: amount,
    });
    let response = await context.fetcher.fetch({
      method: "GET",
      url: url
    });
    let json = response.body;
    return json.rates.USD;
  },
});

View the logs

Coda logs every API request that your Pack makes, and examining those logs can be very useful when troubleshooting.

In the Pack's side panel click the View logs button to bring up the Pack Maker Tools. If you have navigated away from the Pack's panel, click Insert > Packs > {Pack name}.

Where to fine the open logs button in the panel

Find the most recent invocation of your formula (that isn't from the cache) and expand it to reveal the log entry for the fetch request.

Expanding that log entry reveals additional metadata about the request, including the response code and duration.

The fetch request showing in the logs.

Click the link Show HTTP request details under the log entry to bring up a dialog containing the full HTTP request and response. Expand the response body to inspect the JSON structure that was returned by the API.

The raw HTTP request and response.

Next steps

Now that you have an understanding of how to call an external API, here are some more resources you can explore:

  • Fetcher guide - More in-depth information about how to use the fetcher.
  • Sample code - A collection of sample Packs that show how to use the fetcher.
  • Pack maker tools guide - More information on how to view the logs for your Pack.