DEV Community

Lennart
Lennart

Posted on • Originally published at lekoarts.de

Generating QR Codes from any String in Gatsby

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
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
    }
  `)
}
Enter fullscreen mode Exit fullscreen mode

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")
    }
  `)
}
Enter fullscreen mode Exit fullscreen mode

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")
    }
  `)
}
Enter fullscreen mode Exit fullscreen mode

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
    }
  }
`
Enter fullscreen mode Exit fullscreen mode

Top comments (0)