The API call failed because row 37 had no email. Worse, it succeeded with an empty amount. assertRequiredKeys(obj, requiredKeys, opts) checks a row object against a list of required keys and returns { ok, missing }. Blank strings and whitespace-only values count as missing; 0 and false count as present. Pass { throwOnMissing: true } when you’d rather stop than check.
When to use
- Preflight before UrlFetch / CRM / invoicing calls
- Validating Form or import rows before they reach a master tab
- Writing a teammate-readable “Missing: Email, Amount” status instead of a stack trace
How to use this snippet
/**
* Check that a row object has non-blank values for every required key.
*
* @param {Object} obj e.g. { Email: 'a@b.com', Amount: '' }
* @param {string[]} requiredKeys e.g. ['Email', 'Amount']
* @param {{throwOnMissing?: boolean, label?: string}=} opts
* throwOnMissing throw an Error listing missing keys instead of returning
* label prefix for the error, e.g. 'Row 37'
* @return {{ok: boolean, missing: string[]}}
*/
function assertRequiredKeys(obj, requiredKeys, opts) {
opts = opts || {};
obj = obj || {};
var missing = (requiredKeys || []).filter(function (key) {
var v = obj[key];
// undefined / null / '' / ' ' are missing. 0, false and Dates are present.
return v === undefined || v === null ||
(typeof v === 'string' && v.trim() === '');
});
var result = { ok: missing.length === 0, missing: missing };
if (!result.ok && opts.throwOnMissing) {
throw new Error((opts.label ? opts.label + ': ' : '') + 'missing ' + missing.join(', '));
}
return result;
}
Example
var REQUIRED = ['Email', 'Plan', 'Amount'];
function pushRowsToCrm() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Leads');
var rows = readRowsAsObjects_(sheet); // [{ _row, Email, Plan, Amount, Status }, ...]
var statusCol = 5;
rows.forEach(function (row) {
var check = assertRequiredKeys(row, REQUIRED);
if (!check.ok) {
sheet.getRange(row._row, statusCol).setValue('Needs info: ' + check.missing.join(', '));
return; // skip the API call
}
callCrm_(row);
sheet.getRange(row._row, statusCol).setValue('Sent');
});
}
// Or fail loud inside a helper
assertRequiredKeys(payload, ['id', 'email'], { throwOnMissing: true, label: 'Invoice payload' });
Tips:
- Keys are matched exactly.
'Email'and'email 'are different keys, so trim your headers when building row objects. - It checks presence, not format. Pair it with an email regex or number check for fields that need it.
- Want
0to count as missing (e.g. Amount must be positive)? Check that separately; this helper treats0as a real value on purpose. - Keep the
REQUIREDlist next to the code that needs it, so adding a field to the API call and to the check happens in one place.
Tip: NitroGAS Co-Pilot can read an existing API call, list the fields it actually uses, and draft the REQUIRED array for assertRequiredKeys.
Happy Coding!
