knack-api
Version:
Knack API
436 lines (402 loc) • 13.5 kB
text/typescript
const { verifyUserToken } = require("./helpers/verifyUserToken");
const { showCustomModal } = require("./helpers/showCustomModal");
interface rules {
field: string;
operator:
| "is"
| "is not"
| "is blank"
| "is not blank"
| "contains"
| "does not contain"
| "starts with"
| "ends with"
| "is any"
| "is during the current"
| "is during the previous"
| "is during the next"
| "is before the previous"
| "is after the next"
| "is before"
| "is after"
| "is today"
| "is today or before"
| "is today or after"
| "is before today"
| "is after today"
| "is before current time"
| "is after current time"
| "higher than"
| "lower than"
| "near";
value?: string;
range?: number;
type?: string;
}
interface filters {
match: "and" | "or";
rules: rules[];
}
interface sort {
field: string;
order: "asc" | "desc";
}
type contextProp = `${string}_id`;
interface getSettings {
sceneKey: string;
viewKey: string;
recordId?: string;
filters?: filters;
sort?: sort[] | sort;
retry?: boolean;
page?: number;
recordLimit?: number;
rowsPerPage?: number;
cb?: (data: any) => any;
isPublic?: boolean;
context?: Record<contextProp, string>; // page-slug-of-where-the-view-and-scene-is_id=idofrecord
}
interface putSettings {
sceneKey: string;
viewKey: string;
recordId: string;
payload: any;
retry: boolean;
isPublic?: boolean;
}
interface postSettings {
sceneKey: string;
viewKey: string;
payload: any;
retry: boolean;
isPublic?: boolean;
}
interface deleteSettings {
sceneKey: string;
viewKey: string;
recordId: string;
retry: boolean;
}
declare let knack_api: any;
declare const Knack: any;
module.exports.knack_api = {
get: function (
settings: getSettings,
ajaxAttemptsRemaining?: number,
combinedRecords?: any
) {
const { sceneKey, viewKey, recordId, filters, sort, retry, cb, isPublic, context } =
settings;
// if Knack user session has expired we want to show a warning and return without making a network req
if (!isPublic && !verifyUserToken()) {
showCustomModal(
"Session Expired",
"Your session has expired. To prevent network errors and ensure proper functionality, please log out and then log back in."
);
return Promise.reject("User token is invalid.");
}
this.data = {
records: new Promise((resolve, reject) => {
let rowsPerPage = settings.rowsPerPage;
let recordLimit = settings.recordLimit;
//handle retry upon failure
if (!retry) ajaxAttemptsRemaining = 3;
if (!combinedRecords) combinedRecords = {};
if (!settings.page) settings.page = 1;
if (!rowsPerPage || rowsPerPage > 1000) rowsPerPage = 1000;
let reqUrl = `https://api.knack.com/v1/pages/${sceneKey}/views/${viewKey}/records/`;
if (recordId) {
reqUrl += `${recordId}`;
}
if (filters) {
reqUrl += `?filters=${encodeURIComponent(JSON.stringify(filters))}`;
}
if (sort) {
if (Array.isArray(sort)) {
sort.forEach((value: sort) => {
const field = value.field;
const order = value.order;
reqUrl.indexOf("?") == -1
? (reqUrl += `?sort_field=${field}&sort_order=${order}`)
: (reqUrl += `&sort_field=${field}&sort_order=${order}`);
});
} else {
reqUrl.indexOf("?") == -1
? (reqUrl += `?sort_field=${sort.field}&sort_order=${sort.order}`)
: (reqUrl += `&sort_field=${sort.field}&sort_order=${sort.order}`);
}
}
if (context) {
const [key, value] = Object.entries(context)[0];
if (key && value) {
reqUrl.indexOf("?") == -1
? (reqUrl += `?${key}=${value}`)
: (reqUrl += `&${key}=${value}`);
}
}
reqUrl.indexOf("?") == -1
? (reqUrl += `?page=${settings.page}&rows_per_page=${rowsPerPage}`)
: (reqUrl += `&page=${settings.page}&rows_per_page=${rowsPerPage}`);
console.log("Request URL: ", reqUrl);
Knack.$.ajax({
url: reqUrl,
type: "GET",
dataType: "json",
headers: {
"X-Knack-Application-Id": Knack.application_id,
"X-Knack-REST-API-KEY": "knack",
Authorization: Knack.getUserToken(),
"content-type": "application/json",
},
success: function (data: any) {
cb && cb(data);
if (
data &&
data.records &&
data.records.length > 0 &&
data.total_pages > 0
) {
if ((settings.page || 1) < data.total_pages) {
combinedRecords.records
? combinedRecords.records.push(...data.records)
: (combinedRecords = data);
settings.page && settings.page++;
if (recordLimit) {
if (combinedRecords.records.length >= recordLimit) {
if (combinedRecords.records.length > recordLimit)
combinedRecords.records = combinedRecords.records.slice(
0,
recordLimit
);
resolve(combinedRecords);
} else {
resolve(
module.exports.knack_api.get(
settings,
ajaxAttemptsRemaining,
combinedRecords
)
);
}
} else {
resolve(
module.exports.knack_api.get(
settings,
ajaxAttemptsRemaining,
combinedRecords
)
);
}
} else {
combinedRecords.records
? combinedRecords.records.push(...data.records)
: (combinedRecords = data);
if (recordLimit && combinedRecords.records.length > recordLimit)
combinedRecords.records = combinedRecords.records.slice(
0,
recordLimit
);
resolve(combinedRecords);
}
} else {
resolve(data);
}
},
error: function (err: any) {
if (ajaxAttemptsRemaining) {
ajaxAttemptsRemaining--;
settings.retry = true;
console.log(`Ajax get error: ${err}`);
console.log(`Attempts remaining: ${ajaxAttemptsRemaining}`);
resolve(
module.exports.knack_api.get(
settings,
ajaxAttemptsRemaining,
combinedRecords
)
);
} else {
reject(err);
}
},
});
})
.then((result) => {
this.data.result = result;
return this.data.result;
})
.catch((reason) => {
console.log(`Failure reason: ${reason}`);
}),
};
this.data.records.include = async (filterParam) => {
await this.data.records;
this.data.result.records.forEach((record) => {
for (let prop in record) {
if (filterParam.indexOf(prop) == -1) {
delete record[prop];
}
}
});
return this.data.result;
};
this.data.records.exclude = async (filterParam) => {
await this.data.records;
this.data.result.records.forEach((record) => {
for (let prop in record) {
if (filterParam.indexOf(prop) != -1) {
delete record[prop];
}
}
});
return this.data.result;
};
return this.data.records;
},
put: (settings: putSettings, ajaxAttemptsRemaining?: number) => {
const { sceneKey, viewKey, recordId, payload, retry, isPublic } = settings;
// if Knack user session has expired we want to show a warning and return without making a network req
if (!isPublic && !verifyUserToken()) {
showCustomModal(
"Session Expired",
"Your session has expired. To prevent network errors and ensure proper functionality, please log out and then log back in."
);
return Promise.reject("User token is invalid.");
}
return new Promise((resolve, reject) => {
//handle retry upon failure
if (!retry) ajaxAttemptsRemaining = 3;
let reqUrl = `https://api.knack.com/v1/pages/${sceneKey}/views/${viewKey}/records/`;
if (recordId) {
reqUrl += `${recordId}`;
}
console.log("Request URL: ", reqUrl);
Knack.$.ajax({
url: reqUrl,
type: "PUT",
dataType: "json",
headers: {
"X-Knack-Application-Id": Knack.application_id,
"X-Knack-REST-API-KEY": "knack",
Authorization: Knack.getUserToken(),
"content-type": "application/json",
},
data: JSON.stringify(payload),
success: function (data: any) {
resolve(data);
},
error: function (err: any) {
if (ajaxAttemptsRemaining) {
ajaxAttemptsRemaining--;
settings.retry = true;
console.log(`Ajax put error: ${err}`);
console.log(`Attempts remaining: ${ajaxAttemptsRemaining}`);
resolve(
module.exports.knack_api.put(settings, ajaxAttemptsRemaining)
);
} else {
reject(err);
}
},
});
}).catch((reason) => {
console.log(`Failure reason: ${reason}`);
});
},
post: (settings: postSettings, ajaxAttemptsRemaining?: number) => {
const { sceneKey, viewKey, payload, retry, isPublic } = settings;
// if Knack user session has expired we want to show a warning and return without making a network req
if (!isPublic && !verifyUserToken()) {
showCustomModal(
"Session Expired",
"Your session has expired. To prevent network errors and ensure proper functionality, please log out and then log back in."
);
return Promise.reject("User token is invalid.");
}
return new Promise((resolve, reject) => {
//handle retry upon failure
if (!retry) ajaxAttemptsRemaining = 3;
let reqUrl = `https://api.knack.com/v1/pages/${sceneKey}/views/${viewKey}/records/`;
console.log("Request URL: ", reqUrl);
Knack.$.ajax({
url: reqUrl,
type: "POST",
dataType: "json",
headers: {
"X-Knack-Application-Id": Knack.application_id,
"X-Knack-REST-API-KEY": "knack",
Authorization: Knack.getUserToken(),
"content-type": "application/json",
},
data: JSON.stringify(payload),
success: function (data: any) {
resolve(data);
},
error: function (err: any) {
if (ajaxAttemptsRemaining) {
ajaxAttemptsRemaining--;
settings.retry = true;
console.log(`Ajax post error: ${err}`);
console.log(`Attempts remaining: ${ajaxAttemptsRemaining}`);
resolve(
module.exports.knack_api.post(settings, ajaxAttemptsRemaining)
);
} else {
reject(err);
}
},
});
}).catch((reason) => {
console.log(`Failure reason: ${reason}`);
});
},
deletion: (settings: deleteSettings, ajaxAttemptsRemaining?: number) => {
// if Knack user session has expired we want to show a warning and return without making a network req
if (!verifyUserToken()) {
showCustomModal(
"Session Expired",
"Your session has expired. To prevent network errors and ensure proper functionality, please log out and then log back in."
);
return Promise.reject("User token is invalid.");
}
return new Promise((resolve, reject) => {
const { sceneKey, viewKey, recordId, retry } = settings;
//handle retry upon failure
if (!retry) ajaxAttemptsRemaining = 3;
let reqUrl = `https://api.knack.com/v1/pages/${sceneKey}/views/${viewKey}/records/`;
if (recordId) {
reqUrl += `${recordId}`;
}
console.log("Request URL: ", reqUrl);
Knack.$.ajax({
url: reqUrl,
type: "DELETE",
dataType: "json",
headers: {
"X-Knack-Application-Id": Knack.application_id,
"X-Knack-REST-API-KEY": "knack",
Authorization: Knack.getUserToken(),
"content-type": "application/json",
},
success: function (data: any) {
resolve(data);
},
error: function (err: any) {
if (ajaxAttemptsRemaining) {
ajaxAttemptsRemaining--;
settings.retry = true;
console.log(`Ajax delete error: ${err}`);
console.log(`Attempts remaining: ${ajaxAttemptsRemaining}`);
resolve(
module.exports.knack_api.deletion(settings, ajaxAttemptsRemaining)
);
} else {
reject(err);
}
},
});
}).catch((reason) => {
console.log(`Failure reason: ${reason}`);
});
},
};