Using Iris App SDK Proxy

In most cases to call an external API you can just use http client in your app's code and do the requests. But there are
two situations in which you will need to use Iris App SDK Proxy service:

  1. When the external API does not implement CORS or does not allow Trackunit as an origin and the browser will not allow
    the call
  2. To use secrets (like API key) without hardcoding them in your application

Manifest requirements

To use the Iris App SDK Proxy you need to add api.iris.app.proxy.fetch scope (to make calls using Proxy) and
optionally account.iris.app.store-secret scope (to store secrets) to your APPs manifest. Additionally, you need to
specify the domains that your app is allowed to call in the cspHeader "connect-src". So your manifest could look like
this:

const irisAppManifest: IrisAppManifest = {
    // ommiting other config
    cspHeader: {
        ...defaultCspConfig(),
        "connect-src": [...defaultCspConfig()["connect-src"], "https://dbc-1234-567.cloud.databricks.com"],
    },
    scopes: [
        {scope: "api.iris.app.proxy.fetch", optional: false},
        {scope: "account.iris.app.store-secret", optional: false},
    ],
};

Then you need to Publish your application and have it Approved at least once (it can be empty, only the manifest
is important at this stage) so that all required infrastructure is created for it and your app is assigned an AppId and
can get the AppToken. Follow this publication guide for details.
From this point you can develop your application locally. If you change the manifest then you need
to Publish and get Approval once again to unlock the local development mode with the Proxy functionality
working.

Usage

The Iris App SDK Proxy has 2 GraphQL mutations that you can use - irisAppProxyStoreSecrets and irisAppProxyFetch.

To get the latest information about the GraphQL schema
check GraphQL Explorer.

Store secrets

irisAppProxyStoreSecrets mutation allows you to store the secret in our vault so that later you can use it in the
irisAppProxyFetch:

mutation IrisAppProxyStoreSecrets($secrets: JSONObject!) {
  irisAppProxyStoreSecrets(secrets: $secrets) {
    success
    errorMessage
  }
}

The JSON object can be for example "{\"mySecretName\": \"mySecretValue\"}"

To store the secrets you need to have an admin account - that is to have
account.iris.app.store-secret permission. Your app also needs to have account.iris.app.store-secret scope in order
to be able to use this mutation.

After executing irisAppProxyStoreSecrets mutation you can use the secret in the irisAppProxyFetch - the Iris App SDK
Proxy will search for this secret in a header and replace it like this:

"headers": {"name": "Authorization", "value": "Bearer {{mySecretName}}"}

into:

"headers": {"name": "Authorization", "value": "Bearer mySecretValue"}

Perform the request

To perform a request to some external APIs using Proxy service you need to call irisAppProxyFetch GraphQL mutation.
It has 4 arguments: headers, method, url and body. All those arguments are then used to call the external API.

  • url is the endpoint that you want to call (remember to include it in your manifest cspHeader).
  • headers are the headers that will be used in the request. You can include your secrets there using moustache
    format ({{mySecretName}})
  • methodis the method that will be used for the request - it is an enum GET, POST, PUT, DELETE, PATCH
  • body is base64 encoded body that Proxy server will decode and use as the request body

The GraphQL should respond with 200 code if it managed to perform the request regardless of the request result!
Also, the errorMessage field should be empty.

To check the status of the request that the Proxy made on your behalf, you should check the status field. This is the
response status of the url that you've called.
The headers field are the headers that were included in the response of the server that was called by the Proxy.
The body is base64 encoded body that the server responded with.

Example:

mutation IrisAppProxyFetch($url: String!, $headers: [IrisAppProxyHeader!]!, $method: HttpMethod!, $body: String) {
  irisAppProxyFetch(url: $url, headers: $headers, method: $method, body: $body) {
    body
    errorMessage
    headers {
      name
      value
    }
    status
    success
  }
}

The status, headers and body fields are coming from the endpoint specified in url argument.

Common errors:

  • 403 Token does not contain App Id - this error occurs when your app doesn't use the AppToken. It happens when you
    didn't publish the app for the first time, or after the change of manifest. To solve - publish the app
  • 403 CSP 'connect-src' directive does not contain provided URL host - this happens when the url argument of the
    GraphQL call doesn't match with the connect-src from the cspHeader in your manifest. To solve - update the cspHeader
    with your url and publish the app
  • 409 Unresolved placeholders X in header Y - this happens when you've used moustache template in the header like
    {{secret}} but didn't store the secret using irisAppProxyStoreSecrets. To solve - use the
    irisAppProxyStoreSecrets endpoint with the secret value or remove the {{secret}} from your headers.