Want to ship landing pages easily? Cool. Let's do it.
Today, I'm going to show you how to use DatoCMS to manage your content and Gatsby.js to run it.
Prerequisites
Here's what you need to be familiar with:
JavaScript (obviously)
You just need to know what these things are. You don't need to be an expert.
Getting Started
A couple of things you need to do:
Once, you've got an account and set up your Gatsby site - go to the next section.
The Story
Alright, so let's start with the value proposition for why and what we're building:
My name is Juan. I'm on the market for my next engineering role. I want to stand out in the process, instead of sending out a cover letter I'm going to create a landing page and send that with each job application.
Cool. So, we have a bunch of options out there. We can use Wix, Wordpress, etc... But - nah. We're going to use Gatsby + DatoCMS. Why?
Cost effective (free packages on all services)
Easy customization (more control over the code)
Fast delivery (low learning barrier - we're going JAMStack baby!)
Defining the Data Model
If you're not familiar with data modeling, I highly recommend checking out Data Modeling: Ensuring Data You Can Trust. It boils down to this:
An effective data modelling procedure leads to better allocation of human and computational resources, anticipates issues before they arise, bolsters cross-functional communication, and enforces compliance (regulatory and internal) โ all while guaranteeing underlying data quality, security, and accessibility.
We're not going to build out anything complicated, but I think this is important in general, so leaving the above in as informational material for you.
Alright - data model time. Here's the data model we're working with:
CoverLetter
Attributes
Company Name (string)
Job Title (string)
Slug (string)
Introduction (text / html)
Relationships
has many Skills
has many Frequently Asked Questions
Frequently Asked Question
Attributes
Question (string)
Answer (string)
Icon
Attributes
Name (string)
SVG (text / html)
Skill
Attributes
Name (string)
Description (text / html)
Relationships
- has one Icon
DatoCMS - Setting up Models
So we have our data model, let's start setting these up in DatoCMS. We're going to navigate to "Settings" in the top nav and click on "Models" in the sidebar.
To move a bit faster, I'm dropping screenshots below of what these models should look like. Feel free to complete this on your end. For more information around how text fields can be displayed within DatoCMS itself and defining relationships - read the next two sections and then come back here to finish this section up.
Cover Letter
Frequently Asked Question
Icon
Skill
DatoCMS - Text Field Presentations
When you select the "Multiple-paragraph text" option as a field type, you have the ability to customize how that field looks like within DatoCMS's Content area. For example, if we go ahead and edit a "Multiple-paragraph text" field type and hit the "Presentation" tab - we have tha bility to select an HTML Editor:
If we do that, we then see:
This will enable us to essentially add markup in DatoCMS - and then render it within our Gatsby app. So for this tutorial, select "HTML Editor" so we can get some CMS driven content into our app later.
DatoCMS - Defining Relationships
In DatoCMS - relationships are defined as "links".
By defining these relationships, when we go to create the content, we'll be able to select the instances that we create:
In the above example, I've created a "Ruby on Rails" skill - and have associated it with this new cover letter. Nifty, eh?!
Just keep in mind that you'll need to define each model first. Then you'll need to come back and add the links - since the model definition needs to exist for you to select it ๐.
Gatsby.js - Installing and Configuring Dependencies
If you followed the "Getting Started" section of this article - you should have a gatsby site ready.
The first step in connecting DatoCMS is installing gatsby-source-datocms
, you can do this by running:
npm i --save gatsby-source-datocms
or
yarn add gatsby-source-datocms
Either way, you want to have the dependency listed in the dependencies
section of your package.json
:
"gatsby-source-datocms": "^2.3.0",
Note: This was the version being installed at the time of this article.
Once the dependency is installed, let's use and configure it. To do that, let's hit up gatsby-config.js
and add the following to the plugins list:
// more plugins above
{
resolve: `gatsby-source-datocms`,
options: {
apiToken: process.env.CMS_TOKEN,
preview: false,
disableLiveReload: false,
},
},
Note: I've added this at the bottom of my plugins list.
Alright. So if you notice above - we have the following code: apiToken: process.env.CMS_TOKEN
. You need an API token in order to query your data.
I'm using the read only version of the api token, since all I'm doing is presenting data - not modifying it. To get your API token, go to DatoCMS. Hit the "Settings" nav link at the top and then click on "API tokens" under the "Permissions" section of the sidebar. Click on "Read-only API token" and copy that sucker.
Now, you can use a package like dotenv or whatever to load in environment variables - but I'm NOT going to get into that for this article.
I'm simply going to have you run:
CMS_TOKEN=MY_API_TOKEN yarn develop
Note: Update MY_API_TOKEN
with the token you copied earlier.
You won't notice any changes yet because we haven't really done anything user facing yet. Let's push forward!
Gatsby.js - Exploring the Playground
Let's take a moment to understand how we can interact with DatoCMS's api using GraphQL. The best part about using Gatsby.js is that you get GraphQL for free and in order to start experimenting with it - you just need to use the built-in playground.
So, let's run the app:
CMS_TOKEN=MY_API_TOKEN yarn develop
Note: Update MY_API_TOKEN
with the token you copied earlier.
Once that app is running, you can visit http://localhost:8000/__graphql
You should see:
In the playground you can experiment with all the queries available to you, including this one:
The above query fetches all our cover letters.
You can also fetch per the slug field we defined earlier:
Cool right?! Yeah..very cool!
Break Time!
This is a good time to take a break. If you haven't already, put in some content into DatoCMS!
DatoCMS + Gatsby.js - The Perfect Match
Alright. So we installed and configured DatoCMS + Gatsby.js. We added some content to DatoCMS. Now we're ready to connect the dots.
Gatsby.js - Creating Dynamic Pages
Firs things first. We need to retrieve the content from DatoCMS and create landing pages. This requires us to tap into Gatsby.js' API. Specifically, we'll need to use the createPages
function.
So let's go to gatsby-node.js
and drop in the following snippet:
const path = require(`path`)
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
return new Promise((resolve) => {
graphql('
{
allDatoCmsCoverletter {
edges {
node {
slug
}
}
}
}
').then((result) => {
result.data.allDatoCmsCoverletter.edges.map(({ node: coverletter }) => {
createPage({
path: `applications/${coverletter.slug}`,
component: path.resolve(`./src/templates/coverletter-page.js`),
context: {
slug: coverletter.slug,
},
})
})
resolve()
})
})
}
Credit: DatoCMS - Gatsby Portfolio Example
So, what does this do?
It uses the
allDatoCmsCoverletter
query (fromgatsby-source-datocms
) to retrieve all our dataOnce we get the results, we use
createPage
to set a path, define the component to use (which we have not defined yet) and provide the context/slug for that page
Essentially, this allows us to visit http://localhost:8000/applications/COVERLETTER_SLUG
- where COVERLETTER_SLUG
is the slug field value for a CoverLetter instance in DatoCMS.
TL;DR - It brings in the content from a model instance like this one:
Gatsby.js - Defining the template
So we're dynamically creating pages from content defined in DatoCMS - great! Now we need to define the template above so we can render that content.
First, create a directory called templates
inside of src
. Then, add the file coverletter-page.js
inside of templates
.
For confirmation, you should have the following file: src/templates/coverletter-page.js
.
This is the file that will render the content from DatoCMS. So you can style it anyway you want. We're going to keep it simple:
{% raw %}
import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"
const CoverLetter = ({ data }) => {
return (
<Layout>
<div className="my-6">
<section className="mb-6">
<h2 className="text-5xl tracking-tight leading-none uppercase text-center">
{data.datoCmsCoverletter.companyName} //{" "}
{data.datoCmsCoverletter.jobTitle}
</h2>
</section>
{/* SECTION: Introduction */}
<div
dangerouslySetInnerHTML={{
__html: data.datoCmsCoverletter.introduction,
}}
/>
{/* SECTION: Skills */}
<div className="my-10 px-4">
<h3 className="text-base uppercase">My Skills</h3>
<div className="mt-10">
<ul className="grid grid-cols-2 col-gap-8 row-gap-10">
{data.datoCmsCoverletter.skills.map((s) => (
<li>
<div className="flex">
<div className="flex-shrink-0">
<div
className="flex items-center justify-center h-12 w-12 rounded-md bg-indigo-500 text-white"
dangerouslySetInnerHTML={{
__html: s.icon.svg,
}}
></div>
</div>
<div className="ml-4">
<h4 className="text-lg leading-6 font-medium text-gray-900">
{s.name}
</h4>
<p
className="mt-2 text-base leading-6 text-gray-500"
dangerouslySetInnerHTML={{
__html: s.description,
}}
/>
</div>
</div>
</li>
))}
</ul>
</div>
</div>
{/* SECTION: FAQs */}
<div className="my-10 px-4">
<h3 className="text-base uppercase">Frequently Asked Questions</h3>
<div className="mt-10">
<dl className="grid grid-cols-2 gap-8">
{data.datoCmsCoverletter.frequentlyAskedQuestions.map((faq) => (
<div>
<dt className="text-lg leading-6 font-medium text-gray-900">
{faq.question}
</dt>
<dd className="mt-2">
<p
className="text-base leading-6 text-gray-500"
dangerouslySetInnerHTML={{
__html: faq.answer,
}}
></p>
</dd>
</div>
))}
</dl>
</div>
</div>
</div>
</Layout>
)
}
export default CoverLetter
export const query = graphql'
query GetCoverLetter($slug: String!) {
datoCmsCoverletter(slug: { eq: $slug }) {
id
jobTitle
companyName
introduction
skills {
name
description
icon {
svg
}
}
frequentlyAskedQuestions {
question
answer
}
}
}
'
{% endraw %}
Note: We're using dangerouslySetInnerHTML
in order to render HTML content that we have filled in DatoCMS.
Ok. So if you're ready - I'm ready! Let's restart the app and load up http://localhost:8000.
You should see something like this:
Note: Your design will look totally different. I'm using Tailwind + TailwindUI on my personal site - which is why it looks the way that it does above.
๐ ๐ ๐ Congrats! You've made it! ๐ ๐ ๐
What we learned
Data modeling
DatoCMS' Capabilities
Integrating DatoCMS with Gatsby.js
Gatsby.js API using
createPages
andcreatePage
GraphQL fetching and slug matching
and ultimately - enabling us to automate our processes for faster and more reliable delivery using a JAMStack.