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.
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.
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;
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.