forge-server-utils
Version:
Tools for accessing Autodesk Forge APIs from Node.js apps and from browser.
168 lines (148 loc) • 7.76 kB
text/typescript
import axios, { AxiosRequestConfig, AxiosInstance } from 'axios';
import * as rax from 'retry-axios';
import { AuthenticationClient } from './authentication';
const MaxContentLength = Number.MAX_SAFE_INTEGER;
const MaxBodyLength = Number.MAX_SAFE_INTEGER;
export function sleep(ms: number) { return new Promise(function(resolve) { setTimeout(resolve, ms); }); }
export const DefaultHost = 'https://developer.api.autodesk.com';
export enum Region {
US = 'US',
EMEA = 'EMEA'
}
export type IAuthOptions = { client_id: string; client_secret: string; } | { token: string; };
export type IRequestData = { urlencoded: any; } | { json: any; } | { buffer: any; };
export abstract class ForgeClient {
protected auth?: AuthenticationClient;
protected token?: string;
protected root: string;
protected host: string;
protected region: Region;
protected axios: AxiosInstance;
/**
* Initializes new client with specific authentication method.
* @param {string} root Root path for all endpoints (must not contain any slashes at the beginning nor end).
* @param {IAuthOptions} auth Authentication object,
* containing either `client_id` and `client_secret` properties (for 2-legged authentication),
* or a single `token` property (for 2-legged or 3-legged authentication with pre-generated access token).
* @param {string} [host="https://developer.api.autodesk.com"] Forge API host (must not contain slash at the end).
* @param {Region} [region="US"] Forge availability region ("US" or "EMEA").
*/
constructor(root: string, auth: IAuthOptions, host?: string, region?: Region) {
if ('client_id' in auth && 'client_secret' in auth) {
this.auth = new AuthenticationClient(auth.client_id, auth.client_secret, host);
} else if ('token' in auth) {
this.token = auth.token;
} else {
throw new Error('Authentication parameters missing or incorrect.');
}
this.root = root;
this.host = host || DefaultHost;
this.region = region || Region.US;
this.axios = axios.create({
baseURL: this.host + '/' + this.root + '/',
maxContentLength: MaxContentLength,
maxBodyLength: MaxBodyLength
});
// Attach an interceptor to the axios instance that will retry response codes 100-199, 429, and 500-599.
// For default settings, see https://github.com/JustinBeckwith/retry-axios#usage.
this.axios.defaults.raxConfig = {
instance: this.axios
};
rax.attach(this.axios);
}
/**
* Resets client to specific authentication method, Forge host, and availability region.
* @param {IAuthOptions} [auth] Authentication object,
* containing either `client_id` and `client_secret` properties (for 2-legged authentication),
* or a single `token` property (for 2-legged or 3-legged authentication with pre-generated access token).
* @param {string} [host="https://developer.api.autodesk.com"] Forge API host.
* @param {Region} [region="US"] Forge availability region ("US" or "EMEA").
*/
public reset(auth?: IAuthOptions, host?: string, region?: Region) {
if (typeof auth !== 'undefined') {
if ('client_id' in auth && 'client_secret' in auth) {
this.auth = new AuthenticationClient(auth.client_id, auth.client_secret, host);
} else if ('token' in auth) {
this.token = auth.token;
} else {
throw new Error('Authentication parameters missing or incorrect.');
}
}
if (typeof host !== 'undefined') {
this.host = host || DefaultHost;
}
if (typeof region !== 'undefined') {
this.region = region || Region.US;
}
this.axios = axios.create({ baseURL: this.host + '/' + this.root + '/' });
}
protected async setAuthorization(options: any, scopes: string[]) {
options.headers = options.headers || {};
if (this.auth) {
const authentication = await this.auth.authenticate(scopes);
options.headers['Authorization'] = 'Bearer ' + authentication.access_token;
} else {
options.headers['Authorization'] = 'Bearer ' + this.token;
}
}
// Makes a general request and returns the entire response (not just its parsed body)
protected async fetch(config: AxiosRequestConfig) {
return this.axios.request(config);
}
// Helper method for GET requests,
// returning parsed response body or throwing an excetion in case of an issue
protected async get(endpoint: string, headers: { [name: string]: string } = {}, scopes: string[]): Promise<any> {
const config: AxiosRequestConfig = { headers };
await this.setAuthorization(config, scopes);
const resp = await this.axios.get(endpoint, config);
return resp.data;
}
// Helper method for GET requests returning binary data,
// throwing an excetion in case of an issue
protected async getBuffer(endpoint: string, headers: { [name: string]: string } = {}, scopes: string[]): Promise<any> {
const config: AxiosRequestConfig = { headers, responseType: 'arraybuffer' };
await this.setAuthorization(config, scopes);
const resp = await this.axios.get(endpoint, config);
return resp.data;
}
// Helper method for GET requests returning stream data,
// throwing an excetion in case of an issue
protected async getStream(endpoint: string, headers: { [name: string]: string } = {}, scopes: string[]): Promise<any> {
const config: AxiosRequestConfig = { headers, responseType: 'stream' };
await this.setAuthorization(config, scopes);
const resp = await this.axios.get(endpoint, config);
return resp.data;
}
// Helper method for POST requests,
// returning parsed response body of throwing an excetion in case of an issue
protected async post(endpoint: string, data: any, headers: { [name: string]: string } = {}, scopes: string[]): Promise<any> {
const config: AxiosRequestConfig = { headers };
await this.setAuthorization(config, scopes);
const resp = await this.axios.post(endpoint, data, config);
return resp.data;
}
// Helper method for PUT requests,
// returning parsed response body of throwing an excetion in case of an issue
protected async put(endpoint: string, data: any, headers: { [name: string]: string } = {}, scopes: string[]): Promise<any> {
const config: AxiosRequestConfig = { headers };
await this.setAuthorization(config, scopes);
const resp = await this.axios.put(endpoint, data, config);
return resp.data;
}
// Helper method for PATCH requests,
// returning parsed response body of throwing an excetion in case of an issue
protected async patch(endpoint: string, data: any, headers: { [name: string]: string } = {}, scopes: string[]): Promise<any> {
const config: AxiosRequestConfig = { headers };
await this.setAuthorization(config, scopes);
const resp = await this.axios.patch(endpoint, data, config);
return resp.data;
}
// Helper method for DELETE requests,
// returning parsed response body of throwing an excetion in case of an issue
protected async delete(endpoint: string, headers: { [name: string]: string } = {}, scopes: string[]): Promise<any> {
const config: AxiosRequestConfig = { headers };
await this.setAuthorization(config, scopes);
const resp = await this.axios.delete(endpoint, config);
return resp.data;
}
}