rstify-ask
Version:
Restify is a comprehensive npm package that streamlines and enhances the handling of HTTP requests in JavaScript applications.
388 lines (327 loc) • 13 kB
JavaScript
class Cancel {
constructor(message) {
this.message = message;
}
}
class CancelToken {
constructor(executor) {
let cancel;
this.promise = new Promise((resolve, reject) => {
cancel = () => {
reject(new Cancel('Operation canceled by the user.'));
};
executor(cancel);
});
this.throwIfRequested = () => {
if (this.reason) {
throw this.reason;
}
};
}
static source() {
let cancel;
const token = new CancelToken((c) => {
cancel = c;
});
return { token, cancel };
}
}
class CanceledError extends Error {
constructor(message) {
super(message);
this.name = 'CanceledError';
}
}
class RestifyError extends Error {
constructor(message, config, code, request, response) {
super(message);
this.name = 'RestifyError';
this.config = config;
this.code = code;
this.request = request;
this.response = response;
}
}
class HttpStatusCode {
static OK = 200;
static CREATED = 201;
static ACCEPTED = 202;
static NO_CONTENT = 204;
static MOVED_PERMANENTLY = 301;
static FOUND = 302;
static SEE_OTHER = 303;
static NOT_MODIFIED = 304;
static TEMPORARY_REDIRECT = 307;
static PERMANENT_REDIRECT = 308;
static BAD_REQUEST = 400;
static UNAUTHORIZED = 401;
static FORBIDDEN = 403;
static NOT_FOUND = 404;
static METHOD_NOT_ALLOWED = 405;
static CONFLICT = 409;
static GONE = 410;
static PRECONDITION_FAILED = 412;
static UNPROCESSABLE_ENTITY = 422;
static INTERNAL_SERVER_ERROR = 500;
static NOT_IMPLEMENTED = 501;
static BAD_GATEWAY = 502;
static SERVICE_UNAVAILABLE = 503;
static GATEWAY_TIMEOUT = 504;
}
class RestifyHeaders {
// Common headers
static ACCEPT = 'Accept';
static ACCEPT_CHARSET = 'Accept-Charset';
static ACCEPT_ENCODING = 'Accept-Encoding';
static ACCEPT_LANGUAGE = 'Accept-Language';
static AUTHORIZATION = 'Authorization';
static CACHE_CONTROL = 'Cache-Control';
static CONTENT_TYPE = 'Content-Type';
static USER_AGENT = 'User-Agent';
// Content type headers
static CONTENT_TYPE_JSON = 'application/json';
static CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded';
static CONTENT_TYPE_XML = 'application/xml';
static CONTENT_TYPE_TEXT = 'text/plain';
static CONTENT_TYPE_HTML = 'text/html';
static CONTENT_TYPE_MULTIPART = 'multipart/form-data';
// Caching headers
static ETAG = 'ETag';
static IF_MATCH = 'If-Match';
static IF_NONE_MATCH = 'If-None-Match';
static IF_MODIFIED_SINCE = 'If-Modified-Since';
static IF_UNMODIFIED_SINCE = 'If-Unmodified-Since';
// Authentication headers
static WWW_AUTHENTICATE = 'WWW-Authenticate';
// CORS headers
static ACCESS_CONTROL_ALLOW_ORIGIN = 'Access-Control-Allow-Origin';
static ACCESS_CONTROL_ALLOW_METHODS = 'Access-Control-Allow-Methods';
static ACCESS_CONTROL_ALLOW_HEADERS = 'Access-Control-Allow-Headers';
static ACCESS_CONTROL_MAX_AGE = 'Access-Control-Max-Age';
static ACCESS_CONTROL_EXPOSE_HEADERS = 'Access-Control-Expose-Headers';
static ACCESS_CONTROL_ALLOW_CREDENTIALS = 'Access-Control-Allow-Credentials';
// Security headers
static STRICT_TRANSPORT_SECURITY = 'Strict-Transport-Security';
static CONTENT_SECURITY_POLICY = 'Content-Security-Policy';
static X_CONTENT_TYPE_OPTIONS = 'X-Content-Type-Options';
static X_FRAME_OPTIONS = 'X-Frame-Options';
static X_XSS_PROTECTION = 'X-XSS-Protection';
// Cookies and session headers
static SET_COOKIE = 'Set-Cookie';
static COOKIE = 'Cookie';
// Compression headers
static CONTENT_ENCODING = 'Content-Encoding';
static CONTENT_DECODING = 'Content-Decoding';
// Custom headers
static X_CUSTOM_HEADER = 'X-Custom-Header';
}
function isCancel(value) {
try {
return value instanceof Cancel;
} catch (error) {
console.log(error)
}
}
function isRestifyError(value) {
try {
return value instanceof RestifyError;
} catch (error) {
console.log(error)
}
}
function spread(callback) {
try {
return function wrap(arr) {
return callback.apply(null, arr);
};
} catch (error) {
console.log(error)
}
}
function toFormData(obj) {
try {
const formData = new FormData();
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
formData.append(key, obj[key]);
}
}
return formData;
} catch (error) {
console.log(error)
}
}
function formToJSON(formData) {
try {
const jsonObject = {};
formData?.forEach((value, key) => {
// Check if the key already exists in the object
if (jsonObject.hasOwnProperty(key)) {
// If it's an array, push the new value
if (!Array.isArray(jsonObject[key])) {
jsonObject[key] = [jsonObject[key]];
}
jsonObject[key].push(value);
} else {
// If the key doesn't exist, create a new key-value pair
jsonObject[key] = value;
}
});
return JSON.stringify(jsonObject);
} catch (error) {
console.log(error);
}
}
function getAdapter(config) {
try {
// If running in a browser environment
if (typeof window !== 'undefined' && window.fetch) {
return (resolve, reject) => {
const { method, url, headers, data, cancelToken } = config;
const options = {
method,
headers: {
...headers,
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
};
if (cancelToken) {
cancelToken.promise.then((reason) => {
reject(reason);
});
}
fetch(url, options)
.then((response) => {
// Check if the response has a JSON content type
const contentType = response.headers.get('content-type');
const isJsonResponse = contentType && contentType.includes('application/json');
return isJsonResponse
? response.json() // Parse JSON response
: response.text(); // Otherwise, treat as text
})
.then((responseData) => {
// Resolve with parsed data
resolve({
status: responseData.status || 200,
data: responseData,
});
})
.catch((error) => {
// Enhance error logging
console.error('Fetch error:', error);
reject(error);
});
};
}
// If the environment is not recognized
throw new Error('Restify does not support the current environment');
} catch (error) {
console.log(error);
}
}
function mergeConfig(config1, config2) {
// Create a new object to hold the merged configuration
const mergedConfig = Object.assign({}, config1);
// Iterate through config2 and add or overwrite properties in mergedConfig
for (const key in config2) {
if (config2.hasOwnProperty(key)) {
// Special handling for headers, merging them instead of overwriting
if (key === 'headers' && config1.headers && typeof config1.headers === 'object') {
mergedConfig.headers = Object.assign({}, config1.headers, config2.headers);
} else if (key === 'params' && config1.params && typeof config1.params === 'object') {
// Merge params instead of overwriting
mergedConfig.params = Object.assign({}, config1.params, config2.params);
} else {
mergedConfig[key] = config2[key];
}
}
}
return mergedConfig;
}
function restify(config) {
try {
return new Promise((resolve, reject) => {
const adapter = getAdapter(config);
const cancelToken = config.cancelToken;
if (cancelToken) {
cancelToken.promise.then((reason) => {
reject(reason);
});
}
adapter(resolve, reject);
});
} catch (error) {
console.log(error)
}
}
class Restify {
static request(config) {
return restify(config);
}
static get(url, config) {
return restify(mergeConfig(config, { method: 'GET', url }));
}
static delete(url, config) {
return restify(mergeConfig(config, { method: 'DELETE', url }));
}
static head(url, config) {
return restify(mergeConfig(config, { method: 'HEAD', url }));
}
static options(url, config) {
return restify(mergeConfig(config, { method: 'OPTIONS', url }));
}
static post(url, data, config) {
return restify(mergeConfig(config, { method: 'POST', url, data }));
}
static put(url, data, config) {
return restify(mergeConfig(config, { method: 'PUT', url, data }));
}
static patch(url, data, config) {
return restify(mergeConfig(config, { method: 'PATCH', url, data }));
}
static postForm(url, data, config) {
const formData = toFormData(data);
return restify(mergeConfig(config, { method: 'POST', url, data: formData }));
}
static putForm(url, data, config) {
const formData = toFormData(data);
return restify(mergeConfig(config, { method: 'PUT', url, data: formData }));
}
static patchForm(url, data, config) {
const formData = toFormData(data);
return restify(mergeConfig(config, { method: 'PATCH', url, data: formData }));
}
// Added a new method to handle dynamic authorization
static withAuthorization(authorizationToken) {
return {
get: (url, config = {}) => Restify.get(url, mergeConfig(config, { headers: { Authorization: authorizationToken } })),
delete: (url, config = {}) => Restify.delete(url, mergeConfig(config, { headers: { Authorization: authorizationToken } })),
head: (url, config = {}) => Restify.head(url, mergeConfig(config, { headers: { Authorization: authorizationToken } })),
options: (url, config = {}) => Restify.options(url, mergeConfig(config, { headers: { Authorization: authorizationToken } })),
post: (url, data, config = {}) => Restify.post(url, data, mergeConfig(config, { headers: { Authorization: authorizationToken } })),
put: (url, data, config = {}) => Restify.put(url, data, mergeConfig(config, { headers: { Authorization: authorizationToken } })),
patch: (url, data, config = {}) => Restify.patch(url, data, mergeConfig(config, { headers: { Authorization: authorizationToken } })),
postForm: (url, data, config = {}) => Restify.postForm(url, data, mergeConfig(config, { headers: { Authorization: authorizationToken } })),
putForm: (url, data, config = {}) => Restify.putForm(url, data, mergeConfig(config, { headers: { Authorization: authorizationToken } })),
patchForm: (url, data, config = {}) => Restify.patchForm(url, data, mergeConfig(config, { headers: { Authorization: authorizationToken } })),
};
}
}
// Exporting individual components
restify.Cancel = Cancel;
restify.CancelToken = CancelToken;
restify.CanceledError = CanceledError;
restify.RestifyError = RestifyError;
restify.HttpStatusCode = HttpStatusCode;
restify.RestifyHeaders = RestifyHeaders;
restify.isCancel = isCancel;
restify.isRestifyError = isRestifyError;
restify.spread = spread;
restify.toFormData = toFormData;
restify.formToJSON = formToJSON;
restify.getAdapter = getAdapter;
restify.mergeConfig = mergeConfig;
// Exporting individual components
export default Restify;
export { Cancel, CancelToken, CanceledError, RestifyError, HttpStatusCode, RestifyHeaders, isCancel, isRestifyError, spread, toFormData, getAdapter, mergeConfig, formToJSON };