Formatting JSON in a templating language can be difficult if there are optional fields. In particular, trailing commas can cause invalid JSON, which happens often if there are optionally defined fields.
This article shows how to make it safer to template out JSON.
The examples will be using Liquid to template out a LD+JSON snippet of a schema.org Book.
TLDR: use a leading comma instead of a typical trailing comma
{% if book.numberOfPages %}
, "numberOfPages": {{ book.numberOfPages }}
{% endif %}
Basic example
This example is pretty simple:
{
"@context": "http://schema.org",
"@type": "Book",
"name": "{{ book.name }}",
"description": "{{ book.description }}"
}
The name and description are from our Liquid code. Even if there is no name and description, the JSON will render correctly.
More fields
Because our product is a Book
, we can add fields specific to a book, like bookFormat
, isbn
, and numberOfPages
.
{
"@context": "http://schema.org",
"@type": "Book",
"name": "{{ book.name }}",
"description": "{{ book.description }}",
"bookFormat": "Hardback",
"isbn": "{{ book.isbn }}",
"numberOfPages": {{ book.numberOfPages }}
}
Optional fields
What if the bookFormat
is an EBook
instead of a Hardback
, what do we do with the numberOfPages
?
Solution 1: default
We could use a default value:
{
"@context": "http://schema.org",
"@type": "Book",
"name": "{{ book.name }}",
"description": "{{ book.description }}",
"bookFormat": {{ book.bookFormat }},
"isbn": "{{ book.isbn }}",
"numberOfPages": {% if book.bookFormat == "EBook" %} 0 {% else %} {{ book.numberOfPages }} {% endif %}
}
That works, but it is semantically awkward to have a numberOfPages
property on a electronic item.
Solution 2: conditionally add the field
Instead of a default value, we can conditionally add the field:
{
"@context": "http://schema.org",
"@type": "Book",
"name": "{{ book.name }}",
"description": "{{ book.description }}",
"bookFormat": {{ book.bookFormat }},
"isbn": "{{ book.isbn }}",
{% if book.numberOfPages != blank %}
"numberOfPages": {{ book.numberOfPages }}
{% endif %}
}
That makes a lot more sense.
But wait! There's one issue. Do you see it?
If there is no numberOfPages
, then we have invalid JSON because of the trailing comma!
Solution 3: a leading comma
In order to avoid issues with a trailing comma, we can use leading commas:
{
"@context": "http://schema.org",
"@type": "Book",
"name": "{{ book.name }}",
"description": "{{ book.description }}",
"bookFormat": {{ book.bookFormat }},
"isbn": "{{ book.isbn }}"
{% if book.numberOfPages != blank %}
,"numberOfPages": {{ book.numberOfPages }}
{% endif %}
}
Regardless of whether or not the numberOfPages
field exists, the JSON will always be valid!
Even adding as many fields as we need, it will always be valid:
{
"@context": "http://schema.org",
"@type": "Book",
"name": "{{ book.name }}",
"description": "{{ book.description }}",
"bookFormat": {{ book.bookFormat }},
"isbn": "{{ book.isbn }}"
{% if book.numberOfPages != blank %}
,"numberOfPages": {{ book.numberOfPages }}
{% endif %}
{% if book.illustrator != blank %}
,"illustrator": {{ book.illustrator }}
{% endif %}
{% if book.abridged != blank %}
,"abridged": {{ book.abridged }}
{% endif %}
}
Conclusion
It's a pretty simple fix that can save you quite a lot of time debugging invalid JSON.
It helped me, I hope it helps you!