I have a few questions regarding the schema customization.
[
{
"name": "Foo Bar",
"slug": "foo-bar"
},
{
"name": "Fuz Baz",
"slug": "fuz-baz"
}
]
...
mapping: {
"MarkdownRemark.frontmatter.author": `AuthorsJson.alias`,
"MarkdownRemark.frontmatter.category": `CategoriesJson.name`
}
exports.createSchemaCustomization = ({ actions, schema }) => {
const { createTypes } = actions;
const typeDefs = [
`type AuthorsJson implements Node @dontInfer {
alias: String,
name: String
slug: String,
bio: String,
profile: String
posts: [MarkdownRemark] @link(by: "frontmatter.author.alias", from: "alias")
}`,
`type CategoriesJson implements Node @dontInfer {
name: String,
slug: String,
posts: [MarkdownRemark] @link(by: "frontmatter.category.name", from: "name")
}`,
];
createTypes(typeDefs);
}
The bottom-line question is, how do I accomplish frontmatter validation?
categories.json
(e.g. they can't make up their own category)?Thanks!
This is what I have in gatsby-node.js
:
var categories = [];
var aliases = [];
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions
if(node.internal.type === `CategoriesJson`) {
categories.push(node.name);
}
if(node.internal.type === `AuthorsJson`) {
aliases.push(node.alias);
}
if (node.internal.type === `MarkdownRemark`) {
const slug = createFilePath({ node, getNode, basePath: `pages` })
createNodeField({
node,
name: `slug`,
value: slug,
})
if (node.frontmatter.author === null || node.frontmatter.author === undefined) {
throw "Page is missing alias: " + node.fileAbsolutePath;
}
if (aliases.indexOf(node.frontmatter.author) == -1) {
throw "Page has invalid alias: " + node.fileAbsolutePath;
}
if (node.frontmatter.category === null || node.frontmatter.category === undefined) {
throw "Page is missing category: " + node.fileAbsolutePath;
}
if (categories.indexOf(node.frontmatter.category) == -1) {
throw "Page has invalid category ('" + node.frontmatter.category +"'): " + node.fileAbsolutePath;
}
if (node.frontmatter.tags.length > 3) {
throw "Page has more than 3 tags: " + node.fileAbsolutePath;
}
}
}
Is there a better way?
You can simplify all your conditions by:
let categories = [];
let aliases = [];
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions
if(node.internal.type === `CategoriesJson`) {
categories.push(node.name);
}
if(node.internal.type === `AuthorsJson`) {
aliases.push(node.alias);
}
if (node.internal.type === `MarkdownRemark`) {
const slug = createFilePath({ node, getNode, basePath: `pages` })
createNodeField({
node,
name: `slug`,
value: slug,
})
if (!node.frontmatter.author || !aliases.includes(node.frontmatter.author)) {
throw "Page is missing alias: " + node.fileAbsolutePath;
}
if (!node.frontmatter.category || !categories.includes(node.frontmatter.category)) {
throw "Page is missing category: " + node.fileAbsolutePath;
}
if (node.frontmatter.tags.length > 3) {
throw "Page has more than 3 tags: " + node.fileAbsolutePath;
}
}
}
I've also added let
instead of var
, which is kind of deprecated nowadays. Check the difference at https://www.javascripttutorial.net/es6/difference-between-var-and-let/ and replaced the indexOf == -1
for the more semantic includes
.
For the rest, the approach looks quite solid to me, it's a good way.
If front matter is an array, how do I ensure that no more than 3 elements exist in the array?
By default (and as it should be) frontmatter
will be always an object.