zaccl
Version:
The Zoom App Complete Connection Library, a project that handles everything required to build a zoom-integrated app.
154 lines (135 loc) • 4.62 kB
text/typescript
// Import shared helpers
import sendZoomRequest from './sendZoomRequest';
// Import shared types
import VisitEndpointFunc from '../types/VisitEndpointFunc';
import ZoomAPIConfig from '../../types/ZoomAPIConfig';
import ErrorCode from '../types/ErrorCode';
import ThrottleHeader from '../types/ThrottleHeader';
// Import shared classes
import ZACCLError from '../classes/ZACCLError';
/**
* Generates a visit endpoint function
* @author Gabe Abrams
* @author Grace Whitney
* @param zoomAPIConfig the active api configuration
*/
const genVisitEndpoint = (zoomAPIConfig: ZoomAPIConfig): VisitEndpointFunc => {
/**
* Visit a Zoom endpoint
* @author Gabe Abrams
* @param opts object containing all arguments
* @param opts.path Path of the endpoint
* @param opts.method http method to use for the request
* @param opts.action Human-readable description of the task
* @param opts.errorMap map of Zoom errors taken from the API docs
* @param [opts.postProcessor] function that processes the response before
* returning
* @param [opts.params] Parameters/args/body to send with request
* @returns response body
*/
return async (
opts: {
path: string,
method: ('GET' | 'POST' | 'PUT' | 'DELETE'),
action: string,
errorMap: {
[k: number]: (
| string
| {
[k: number]: string
}
)
},
params?: { [k: string]: any },
postProcessor?: (response: any) => any,
},
): Promise<any> => {
const {
path,
params,
action,
errorMap,
postProcessor,
} = opts;
const method = (opts.method ?? 'GET');
/* ---------- Send Request ---------- */
const { status, headers, body } = await sendZoomRequest({
path,
method,
params,
zoomAPIConfig,
});
/* ----------- Rate Error ----------- */
if (status === 429) {
// Case-insensitive header lookup
const [rateLimitTypeHeader] = Object.keys(headers).filter((header) => {
return (header.toLowerCase() === 'x-ratelimit-type');
});
// Case-insensitive limit type lookup
const rateLimitType = (
headers[rateLimitTypeHeader]
&& headers[rateLimitTypeHeader].toLowerCase()
);
if (rateLimitType === ThrottleHeader.DailyLimitHeader) {
// Daily limit
throw new ZACCLError({
message: 'Zoom is very busy today. Please try this operation again tomorrow.',
code: ErrorCode.DailyLimitError,
});
} else if (rateLimitType === ThrottleHeader.RateLimitHeader) {
// Rate limit
throw new ZACCLError({
message: 'Zoom is very busy right now. Please try this operation again later.',
code: ErrorCode.RateLimitError,
});
} else {
// Unknown rate limit
throw new ZACCLError({
message: 'Zoom is very busy right now. Please try this operation again.',
code: ErrorCode.UnknownLimitError,
});
}
}
/* -------- Custom Error Code ------- */
if (status < 200 || status >= 300) {
// A Zoom error occurred
// Check status to see if its in the error map
let zoomErrorMessage = 'An unknown Zoom error occurred.';
if (errorMap[status]) {
if (typeof errorMap[status] === 'string') {
// Found the error message
zoomErrorMessage = (errorMap[status] as string);
} else if (body.code) {
// Check for nested error message
if (typeof errorMap[status][body.code] === 'string') {
// Found nested error message
zoomErrorMessage = errorMap[status][body.code];
} else if (body.message) {
// errorMap[status][code] did not return err message
// so we check body
if (typeof body.message === 'string') {
zoomErrorMessage = body.message;
}
}
}
} else if (body.message) {
// Error message not in the error map so check body
if (typeof body.message === 'string') {
zoomErrorMessage = body.message;
}
}
const errorMessage = `We couldn't ${action} because an error occurred: ${zoomErrorMessage}`;
const errorCode = `ZOOM${status}${body.code ? `-${body.code}` : ''}`;
throw new ZACCLError({
message: errorMessage,
code: errorCode,
});
}
/* ----- Post-process and Return ---- */
if (postProcessor) {
return postProcessor(body);
}
return body;
};
};
export default genVisitEndpoint;