Validating records

Check a batch of records, and report every problem without stopping.

What to build

A validator that uses its own error class, and a summary at the end.

Requirements

  • Each line should be JSON with a name and an age.
  • If the line is not valid JSON, print bad json.
  • If name is not a non-empty string, print invalid name. That includes JSON which is not an object.
  • If the name is fine but age is not a number from 0 to 150, print invalid age.
  • Otherwise, print ok NAME.
  • Finally, print summary: X ok, Y invalid, Z bad json.

Input

Several lines of text.

Output

One line per input line, then the summary.

Constraints

There are from 1 to 50 lines.

Example

Input:

{"name":"Mitu","age":21}
{"name":"","age":3}
not json

Output:

ok Mitu
invalid name
bad json
summary: 1 ok, 1 invalid, 1 bad json

Why it works

A custom error class carries the name of the bad field up to the code that does the reporting. The catch block uses instanceof to respond correctly to each kind of failure, and re-throws anything it did not expect.

Examples

Example 1 · Input
{"name":"Mitu","age":21}
{"name":"","age":3}
not json
Expected output
ok Mitu
invalid name
bad json
summary: 1 ok, 1 invalid, 1 bad json
Example 2 · Input
{"name":"A","age":0}
Expected output
ok A
summary: 1 ok, 0 invalid, 0 bad json

Hints

Hint 1

class ValidationError extends Error can store a field name in this.field.

Hint 2

record?.name protects you when the JSON is null.

Hint 3

Parse first, then validate. Use instanceof to tell your error from a SyntaxError.

Solution

Show one correct solution (try it yourself first)
class ValidationError extends Error {
  constructor(field) {
    super(`invalid ${field}`);
    this.name = "ValidationError";
    this.field = field;
  }
}

function validate(record) {
  if (typeof record?.name !== "string" || record.name === "") {
    throw new ValidationError("name");
  }
  if (typeof record.age !== "number" || record.age < 0 || record.age > 150) {
    throw new ValidationError("age");
  }
}

const totals = { ok: 0, invalid: 0, bad: 0 };
let line = prompt();
while (line !== null) {
  try {
    const record = JSON.parse(line);
    validate(record);
    totals.ok++;
    console.log(`ok ${record.name}`);
  } catch (err) {
    if (err instanceof ValidationError) {
      totals.invalid++;
      console.log(err.message);
    } else if (err instanceof SyntaxError) {
      totals.bad++;
      console.log("bad json");
    } else {
      throw err;
    }
  }
  line = prompt();
}
console.log(`summary: ${totals.ok} ok, ${totals.invalid} invalid, ${totals.bad} bad json`);

Lesson: Errors: throw, try and catch →