Optional/required

Unlike with querying values you can, but don't need to specify whether elements queried from the document are optional or required. As you will most often use the elements' values themselves, the necessity for the element hierarchy in between the document and that value is automatically inferred by whether the value itself is optional or required:

document.section('content').section('translated').field('revision').optionalStringValue();

The line above can be run for an entirely empty document and still return null, while by modifying the query of the value itself to be required would make the code throw an error for the first element missing in that hierarchy instead (again assuming an empty document):

document.section('content').section('translated').field('revision').requiredStringValue();

This would produce an error:

The section 'content' is missing - in case it has been specified look for typos and also check for correct capitalization.

   Line | Content
 *    1 | 

With that said, there will of course also be cases where you want to be explicit about whether an element is optional or required, for this you can use the explicit optional* or required* accessor variant, which exists for all element types, for instance:

document.requiredField('author');
document.optionalSection('notes');

As with value accessors, the optional* variants return null if the element does not exist (be aware that you should not chain further queries after such a call because you'd potentially be calling a function on null), while the required* variants immediately throw an error when the element is missing (here you can safely chain further queries afterwards).

Below is a pattern you might find useful, it's basically saying "There always has to be a field with the key 'author', but it can be empty". It returns null or the value, and only throws an error when the field itself is missing.

document.requiredField('author').optionalStringValue();

The pattern below is sort of the reverse, it's "If there is a field with the key 'author', it also requires a value", and guarantees there is a value if there is also a field, otherwise an error is thrown.

const author = document.optionalField('author');

if(author) {
  const value = author.requiredStringValue();
  // ...
}

Last but not least a pattern that does not work:

const author = document.field('author');

if(author) {
  // Will always enter here, author is never null
}

As shown earlier you can safely and deeply query a non-existing document hierarchy. This is possible because the standard query methods return proxy objects (e.g. MissingSection) instead of null when an element in the chain is missing, and with that it's clear why the previous example does not work, instead you have to use the explicit optionalField accessor to ensure you are being returned null if there is no element.

const author = document.optionalField('author');

if(author) {
  // This works, author can be null now
}

Next page: Dynamic layouts