The purpose of the apps proxy is to safely allow your app to communicate with the outside world in a controlled way. The four main aspects of the proxy are:
Whitelist – The proxy is essentially a whitelist of allowed URLs and HTTP methods that you might use when communicating with an API. These URLs are defined concretely or as regular expressions
Timeouts – For each URL in the proxy configuration you can configure a timeout in seconds. This is the maximum amount of time the proxy will wait for a response from another server
Settings Injection – Some APIs require some form of authentication, and this is usually based on a “secret” or “key” that must be configured.
State injection - State and user state set by an app may be injected by the proxy
Configuration
Configuring the proxy is done inside the app manifest in the root of your project. You can configure the proxy with as many "rules" as you like, and each rule requires the following parameters:
url
- the URL pattern of the request (literal string or regular expression) (required)methods
- an array of HTTP methods allowed by this rule (required)timeout
- maximum timeout of this rule in seconds (required)
Below is an example manifest proxy configuration:
{
"name": "my_app",
"title": "My App",
"description": "Brief description of my app",
"version": "1.0.0",
"scope": "agent",
"isSingleInstall": true,
"targets": [{
"target": "ticket_sidebar",
"entrypoint": "index.html"
}],
"settings": {
"api_key": {
"title": "API Key",
"description": "Key for an API",
"type": "string",
"isRequired": true,
"isBackendOnly": true
}
},
"proxy": {
"whitelist": [{
"url": "https://example.com/api/.*",
"methods": ["GET", "POST"],
"timeout": 10
}]
}
} copy
In this example the proxy is configured with a single rule, allowing GET
or POST
on any sub path of the URL regular expression pattern https://example.com/api/.*
(with a 10 second timeout)
Setting Injection
In the previous example we also configured a setting with the name api_key
, with the isBackendOnly
flag set to "true". This means that we can use this setting exclusively in out proxy to pass a secret along with the request. To do this, we use the placeholder format "__<setting_name>__". So, in this example our placeholder would be "__api_key__". Here's an example of us injecting the setting into the URL of an outbound request:
import { useEffect, useState } from "react";
import {
useDeskproAppClient,
proxyFetch,
Fetch,
} from "@deskpro/app-sdk";
export const MyComponent = () => {
const [users, setUsers] = useState<string[]>([]);
const { client } = useDeskproAppClient();
useEffect(() => {
// Is the Deskpro app client initialised?
if (!client) {
return;
}
// First, we need to get a special version of fetch() that is authorised to use the apps proxy
proxyFetch(client).then((fetch: Fetch) => {
// Perform GET request against the API, replacing __api_key__ with the associated setting value
fetch("https://example.com/api/users?key=__api_key__").then((res: Response) => {
// Get data from the API and set state
res.json().then((data) => {
setUsers(data);
});
});
});
}, [client]);
return (
<>
{users.map((user: string, idx: number) => (
<div key={idx}>{user}</div>
))}
</>
);
}; copy
You can also inject settings into whitelist URLs. This is handy for when you may have a user-defined setting that affects an API URL in some way, e.g.
"proxy": {
"whitelist": [{
"url": "https://__domain__/api/.*",
"methods": ["GET", "POST"],
"timeout": 10
}]
} copy
Where __domain__
is a setting, representing a user-defined domain name used for API requests that must be validated by the proxy.
Advanced Settings Injection
Injecting plain string values is fine for the majority of use cases, however there are some occasions where you need to encode a value or even concatenate it with another setting or even a string literal. An example of this is in HTTP basic authorization.
Let's say we have a header like this:
Authorization: Basic dGVzdHVzZXI6dGVzdGtleQ== copy
As you can see, the authorization token itself is base64 encoded. Not only that, it has a string literal of :
separating the two values. The plain, unencoded value looks like this:
Authorization: Basic testuser:testkey copy
When injecting settings we can do the following:
Authorization: Basic __username + ':' + api_key.base64__ copy
Ok, so there's quite a lot going on in this placeholder expression; let's break it down.
We have two settings, "username" and "api_key"
We use the "+" operator to concatenate ":" in-between them
We append the "base64" filter to the end using "." (dot) notation
Available Filters:
base64
- base64 encode the setting valueurlencode
- URL encode the setting value
You can also chain filters together, like this:
__username.base64.urlencode__ copy
State Injection
Similar to settings injection, we may also inject state values into outbound requests if the state values are "scalar", i.e. string or number. We use a different delimiter format for state values as state names may conflict with those of settings. These formats are: "[[<state_name>]]" or "[user[state_name]]" for user state.
In the following example we'll inject the user state value for params/my-secret
:
import { useEffect, useState } from "react";
import {
useDeskproAppClient,
proxyFetch,
Fetch,
} from "@deskpro/app-sdk";
export const MyComponent = () => {
const [users, setUsers] = useState<string[]>([]);
const { client } = useDeskproAppClient();
useEffect(() => {
// Is the Deskpro app client initialised?
if (!client) {
return;
}
// First, we need to get a special version of fetch() that is authorised to use the apps proxy
proxyFetch(client).then((fetch: Fetch) => {
// Perform GET request against the API, replacing [user[params/my-secret]] with the associated state value
fetch("https://example.com/api/users?key=[user[params/my-secret]]").then((res: Response) => {
// Get data from the API and set state
res.json().then((data) => {
setUsers(data);
});
});
});
}, [client]);
return (
<>
{users.map((user: string, idx: number) => (
<div key={idx}>{user}</div>
))}
</>
);
}; copy
Responses
Sometimes we encounter errors when using 3rd party APIs. However, as we're communicating via a proxy, we need to know if the response we received was from the remote system or the proxy itself. For this, we can check the X-Original-Status
response header. If this header is set, then the response originated from the remote system. If this value is not set, then the HTTP status code of the reponse is from our proxy.
Log in of registreer om een reactie te plaatsen.