Lennart
Posted on August 6, 2021
One of the many side-effects of the coronavirus pandemic is that the QR code got some attenion (again). When it first came out you saw it everywhere but the last couple of years it slowly vanished again -- until now where your vaccination certificate or check-in apps all use QR codes again.
Generating QR codes from any string you wish in Gatsby could be done in multiple ways. Normally for such operations you'd set up a transformer plugin but realistically you wouldn't want every string to be converted to a QR code. Thus you can use the createSchemaCustomization API to individually add a new field to your desired node and transform a specific sibling field. This saves work & build time! You can take this YAML schema as an example:
- name: Author's Homepage
description: Visit the author's homepage for more information and other cool stuff
link: https://www.lekoarts.de
Gatsby will generate a InformationYaml
type out of it and you want to have an additional field called qrCodeDataURL
that contains the data URI of a QR code generated from the link
field. Then you can query it like this:
query {
informationYaml {
name
link
description
qrCodeDataURL
}
}
Continue reading to learn how to do this! You can find the finished code on Codesandbox and you can also check out Filter Future Posts on a Gatsby Blog to see the API in a similar example.
Setup
I'm assuming that you already have a Gatsby project set up with some specific fields you want to convert. If not, you can run npm init gatsby
and choose the markdown option. Then you can use the frontmatter to add an additional field. Stop your development server if it's still running.
My example is using a YAML file that is represented as InformationYaml
in the GraphQL schema of Gatsby. You've seen the shape of it in the intro of this post.
Install two dependencies you'll need:
npm install lodash.get qrcode
Generating QR codes
Open your gatsby-node.js
file and add the installed package, and the boilerplate to use Gatsby's schema customization API:
const get = require("lodash.get")
const QRCode = require("qrcode")
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes, createFieldExtension } = actions
}
With the function createTypes
you'll explicitly define the GraphQL types (in this case in GraphQL SDL syntax), with createFieldExtension
you'll create a so called directive/extension that you then can reuse throughout your types.
Adding the new field to the type
Since the QR code should be available at the field qrCodeDataURL
it needs to be added to the desired GraphQL type.
const get = require("lodash.get")
const QRCode = require("qrcode")
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes, createFieldExtension } = actions
createTypes(`
type InformationYaml implements Node {
qrCodeDataURL: String
}
`)
}
But if you'd query this field now you'd only get null
as a result. The data needs to be generated first before querying it.
Creating the field extension
Use the createFieldExtension
action to create a custom directive that you can use on the newly created qrCodeDataURL
field:
const get = require("lodash.get")
const QRCode = require("qrcode")
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes, createFieldExtension } = actions
createFieldExtension({
name: "createQRCode",
args: {
fieldName: "String!",
},
extend({ fieldName }) {
return {
resolve: createQRCode(fieldName),
}
},
})
createTypes(`
type InformationYaml implements Node {
qrCodeDataURL: String @createQRCode(fieldName: "link")
}
`)
}
But the last piece to this puzzle is missing: The createQRCode
function. The field extension will use result of it as the value of the qrCodeDataURL
field. createQRCode
gets passed all the fieldName
you use (in this example "link"
).
const get = require("lodash.get")
const QRCode = require("qrcode")
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes, createFieldExtension } = actions
const createQRCode = (fieldName) => async (source) => {
const string = get(source, fieldName)
let qrCode = ``
try {
qrCode = await QRCode.toDataURL(string, { scale: 6 })
} catch (err) {
console.error(err)
}
return qrCode
}
createFieldExtension({
name: "createQRCode",
args: {
fieldName: "String!",
},
extend({ fieldName }) {
return {
resolve: createQRCode(fieldName),
}
},
})
createTypes(`
type InformationYaml implements Node {
qrCodeDataURL: String @createQRCode(fieldName: "link")
}
`)
}
You can find more information about qrcode
's options on its GitHub page.
Using the result
Now you're able to query the new data! Start the development server and visit GraphiQL at localhost:8000/___graphql
. If you explore the schema you should see qrCodeDataURL
now. You can use this data URI as an image now, for example:
import * as React from "react"
import { graphql } from "gatsby"
export default function Home({ data }) {
return (
<main>
<h1>{data.info.name}</h1>
<p>
{data.info.description}: <br />{" "}
<a href={data.info.link}>Visit the website</a> or scan this QR code:
</p>
<img
alt="QR Code to the authors homepage"
src={data.info.qrCodeDataURL}
/>
</main>
)
}
export const query = graphql`
{
info: informationYaml {
name
link
description
qrCodeDataURL
}
}
`
Posted on August 6, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.