Skip to main content

Provider

The Provider class wraps a small fetch utility that allows you to quickly and efficiently communicate with your Integration's provider.

Options

rateLimiter

Function to limit the rate of calls to the provider based on the caller's credentials and other contextual constraints.

Receives the credentials and logger from the RequestOptions and a callback to call if rateLimiter allows and needs to return the provider's Response. The rateLimiter can thus access the Provider's response headers to do any rate limiting related stuff you may need.

const provider = new Provider({
rateLimiter: (options: { credentials: Credentials, logger: logger }, callback: () => Promise<Response<T>>): Promise<Response<T>> => {
const rateLimitAvailable = getRemainingRateLimit(context.credentials); // to define depending on Provider

if (rateLimitAvailable > 0) {
const response: Response<T> = await callback();

if (response.headers.remainingLimit) {
// ... Update remaining limit as necessary
}

return response;
} else {
throw new HttpErrors.RateLimitExceededError();
}
}
});

See Rate Limiting's recipe for more information.

prepareRequest

Function to define the provider's base URL and specific headers to add to each request. Receives the credentials and logger from the RequestOptions.

const provider = new Provider({
prepareRequest: (options: { credentials: Credentials, logger: logger }) => {
return {
url: 'api.provider.com',
headers: {
Authorization: `Bearer ${options.credentials.apiKey}`
}
};
}
});

By default, the SDK will use JSON headers when talking with your provider. If you need something else, the prepareRequest function is your way to overwrite them.

Methods

get()

Issues a GET requests.

declare function get<T>(endpoint: string, options: RequestOptions): Promise<Response<T>>;

patch()

Issues a PATCH requests.

declare function patch<T>(endpoint: string, body: Record<string, unknown>, options: RequestOptions): Promise<Response<T>>;

delete()

Issues a DELETE requests.

declare function delete<T = undefined>(endpoint: string, options: RequestOptions): Promise<Response<T>>;

post()

Issues a POST requests.

declare function post<T>(endpoint: string, body: Record<string, unknown>, options: RequestOptions): Promise<Response<T>>;

put()

Issues a PUT requests.

declare function put<T>(endpoint: string, body: Record<string, unknown>, options: RequestOptions): Promise<Response<T>>;

Types

RequestOptions

Additional information to be sent with a request.

info

Note that the queryParams here are those you want to add to the call to be made to the provider. They are most likely different than those received through the Context.query object which contains the query params your integration received and may contain Unito specific one (e.g. select and filter). To avoid errors, we named them differently to prevent inadvertently passing them as is, without cherry picking what you really need to call your provider.

interface RequestOptions {
credentials: Record<string, unknown>;
signal: AbortSignal;
logger: Logger;
queryParams?: Record<string, string>;
additionnalheaders?: Record<string, string>;
}

Response

The returned type of any of the above functions. Gives access to the status code and headers returned by the provider in case you have special cases that need those, and the body containing any returned data typed.

interface Response<T> {
body: T;
status: number;
headers: Record<string, string>;
}

Example

Typically, a provider will be instantiated once and then imported wherever needed.

./provider.ts
import { Provider } from '@unito/integration-sdk';

const provider = new Provider({
prepareRequest: options => {
return {
url: 'https://example.com/api',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${options.credentials.apiToken}`
},
};
},
});

export default provider;

From any handler, the provider can then be called as follow;

./handlers/example.ts
import provider from '../provider.js';

const getItem = (context) => {
const response = await provider.get<{ data: { name: string } }>('/my-item', {
credentials: context.credentials,
signal: context.signal,
logger: context.logger,
queryParams: { foo: 'bar' },
additionalHeaders: { query_specific_header: 'baz' }
});

return {
fields: { name: response.body.name },
relations: [],
}
}

If you find yourself with different endpoints requiring completely different setup, don't hesitate to instantiate more than just one provider, importing the ones you need as you go. This is particularly useful when some endpoints have different rate limits than others.