Back

Building a photo gallery app with Gatsby and GraphCMS

Building a photo gallery app with Gatsby and GraphCMS

Most modern websites and apps now make use of backend-only content management systems. With GraphCMS being one of the most popular to use in developing our web applications. With the help of a content management system, we won’t have to spend much time setting up a server and database, writing APIs with which the front end can send and receive data to and from the backend. GraphCMS helps us deal with these hassles so that we can focus on building our application.

Architecture for the Project

In this tutorial, we will look at connecting the GraphCMS to Gatsby and fetch some data using Graphql. We will look at getting started with GraphCMS and setting it up. Since we are building a photo gallery app, we will make all image data available in our GraphCMS API and attach Gatsby.js to the front end. We will create a model and update the content in our GraphCMS admin dashboard. We will then be able to request to get each of the photos displayed on our front end.

Before we dive into building our project, let’s first understand what a Headless CMS is and its need.

What’s a Headless CMS, and why do we need one?

Headless CMS is a content management system that provides a way to manage content. Instead of having your content together in a particular output, it provides your content as data over an API, making it very easy to share your data across multiple devices.

Earlier, Traditional CMS gave us the idea of having all our content, templates, and assets (images, videos) in a single environment. However, this method of serving the content is insufficient concerning how data can be distributed. Having a Headless CMS system is a developmental advance that prompts an even better way of managing content. The structure is flexible, content is treated as data and provided over an API to be served across multiple devices, and content editors work in tailored real-time collaboration environments.

Why use Gatsby?

Gatsby is an open-source framework that enables developers to make blazing fast, search engine-friendly, secure, and powerful websites. It uses a React-based framework and innovative data layer that makes integrating different content, APIs, and services into one web experience effortless. Gatsby builds websites and apps with modern front-end technologies such as ReactJS, Webpack, GraphQL, ES6+ JavaScript, and CSS.

Gatsby provides a way for us to source data from various headless CMSs such as WordPress, GraphCMS, Strapi, Contentful, etc., through plugins.

Why use GraphCMS?

GraphQL offers many advantages such as predictability, performance, development speed, stability, and flexibility. GraphCMS adopts that strategy and does it admirably. GraphCMS makes it easy to integrate with Netlify, Vercel, and Gatsby Cloud for a quick preview. It has remote fields which allow you to pull multiple sources of information into a single API. It automatically generates GraphQL queries from content. It also has built-in localization and locale-based publishing, allowing editors to localize and translate content into any language. You can check out the other notable features GraphCMS offers here.

Now that you have a little grasp of what a headless CMS means, the need for it, why we choose Gatsby for our front end and GraphCMS to handle our backend. Let’s dive into building our jam stack project.

Prerequisites

To follow this tutorial, you need:

Prepare GraphCMS

First, you need to sign up for a GraphCMS account so that you can access our admin panel. You will be given the option to either sign up with Facebook, Google, or Github or fill out some information. It’s up to you.

Signing up for GraphCMS

After signing up, you’ll be directed to this page. Click on the plus icon that says blank for a new project.

Creating a project

Here you can give your project a name. In our case, we’re naming the project Photo gallery. You will be required to choose a server where your data will be stored. Then we will create the project.

Picking a plan for your project

Another cool feature GraphCMS provides is its generous free plan where you have access to all the basic functions: 5 project users, localization, content stages, etc. In our case, we are making use of a free plan.

Creating Schemas

On our admin dashboard, on the left, below environments, click on Schemas, and we will create a model.

Creating a model

When we click add model, a modal opens up where we can create our photo content type and name it Photos. We clicked on continue, and now we can add fields to our content.

The "name" field

Click on the single line text on the right-hand side, and a modal will pop up, as shown in the image above. We will be creating three text fields: the photo gallery app’s title, the photo’s name, and the photo’s source. We will check the use as the title field because we will use it as the project’s title.

The "description" field

We will click on another field and select multi-line text, but this time we name its description as it will be the name and the source of the photo. As shown in the image above, we also checked the allow multiple values option.

The "image" field

Lastly, we created an asset picker field. You can find it by scrolling down to the field options. We named it image, and this will be the image that will be displayed.

The results

Adding our Photos

We go to content editing below the schema and click on the create item button at the top right side.

Editing content

Here you can see the first photo created in the image above with the fields we created earlier. We fill within the input fields with the specified information.

  • The name field is for the name of each photo.
  • The description field is for the photo description.
  • The image field is for the image that will be displayed on our photo gallery app.

To add an image to the app, click on add an existing image, a modal will appear, and you will see the upload button; click on it. You will see the options provided to you, so it’s uploaded to you to select your choice. Then click on upload.

Adding assets

After filling out the information and adding the image, click on the save and publish button. Then you can go back and create more items. In our case, we are creating nine items.

Setting up Roles and Permissions

Before we begin to query this data inside Gatsby, we need to first get our API endpoint and set public permission to open or query any published content.

Setting permissions

Now head to settings, and inside the API access, you will see the endpoints. By default, it’s on content from stage publishing and hit create permission. This means anybody accessing this URL can make a public API request without any authentication required.

Setting up our Gatsby Front end

In this section, we will set up Gatsby and build the photo gallery app UI. so let’s start installing Gatsby CLI. Gatsby command-line interface (CLI) is a tool that allows you to snappily create new Gatsby-powered sites and run commands for developing Gatsby sites. On your terminal, run the subsequent command:

npm install -g gatsby-cli
// to check if it is installed
gatsby --version

With the command line interface installed, we can now create our Gatsby project.

gatsby new

You will be asked a few questions.

What would you like to call your site?
· Photo Gallery App
✔ What would you like to name the folder where your site will be created?
.Desktop/ photo-gallery-app
✔ Will you be using a CMS?
· No (or I'll add it later)
✔ Would you like to install a styling system?
· No (or I'll add it later)
✔ Would you like to install additional features with other plugins?
· Done
Thanks! Here's what we'll now do:

    🛠  Create a new Gatsby site in the folder my-first-gatsby-site

? Shall we do this? (Y/n) › Yes
🎉  Your new Gatsby site Photo Gallery App has been successfully created

Once it is done installing, let’s first cd into our project and install some plugins and dependencies.

cd photo-gallery-app

What we are going to install:

Configuring our dependencies

Let’s start by installing Tailwind CSS. In our project folder, let’s run the following commands:

npm install -D tailwindcss postcss autoprefixer gatsby-plugin-postcss
npx tailwindcss init -p

We have installed tailwind CSS, postcss, autoprefixer, and gatsby-plugin-postcss.

// gatsby.config.js
module.exports = {
  plugins: [
    'gatsby-plugin-postcss',
    // ...
  ],
}

On your gatsby-config.js file, enable the gatsby-plugin-postcss.

// tailwind.config.js

module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Add paths to all of your template files in your tailwind.config.js file.

@tailwind base;
@tailwind components;
@tailwind utilities;

Create a ./src/styles/global.css file and add the @tailwind directives for each of the Tailwind layers.

// gatsby-browser.js

import './src/styles/global.css';

Create a gatsby-browser.js file at the root of your project if it doesn’t already exist, and import your newly-created ./src/styles/global.css file.

Install the GraphCMS plugin

We will be using CLI to install the plugin by running this command on your terminal:

npm install gatsby-source-graphql

With gatsby-source-graphql, you can integrate third-party APIs, like GitHub’s, APIs of services like GraphCMS, and your custom GraphQL API.

Configuring the GraphCMS plugin

Add the following code to the gatsby-config.js file.

module.exports = {
  siteMetadata: {
    siteUrl: "https://www.yourdomain.tld",
    title: "PhotoGallery",
  },
  plugins: [
    'gatsby-plugin-postcss',
    {
      resolve: 'gatsby-source-graphql',
      options: {
        typeName: 'GraphCMS',
        fieldName: 'gcms',
        url: 'https://api-eu-west-2.graphcms.com/v2/ckxcnz96d3srk01xi0skjbq9g/master',
      }
    },
  ],
};

Here we are configuring the graphCMS `graphql“ plugin to be able to query our data through graphCMS API.

  • Line 11: we specify the arbitrary name for the remote schema query type.
  • Line 12: field under which the remote schema will be accessible. You can use this in your Gatsby query
  • Line 13: URL to query from

Query the data in Gatsby GraphiQL

Now that the API endpoint is set up, we will be able to query the data with Gatsby’s GraphiQL playground, and we can shape the query we want to use to display the data here.

First of all, we need to start our server before accessing the Gatsby GraphiQL UI.

gatsby develop

We used this command to start our server. Now that our server has started, we run our site and the Graphql playground on the link provided to us.

Starting our server

By clicking on the links provided, it will bring up the Gatsby GraphQl UI, where we can shape the data we want to query.

query myQuery {
  gcms {
    photo {
      id
      name
      description
    }
  }
}

You’ll see the available fields where we can select the gcms field we defined in the gatsby-source-graphql plugin.

Choosing the fields we created in GraphCMS and then running the query will show our defined data.

Using Asset Transformation API

We will also need to grab the images that we want to display. We do this by making use of asset transformation API. We will be able to grab our image URLs, and we can extend them by passing arguments on to them. You can read more about the asset transformation API.

image {
  url(transformation: {image: {resize: {width: 500, height: 500, fit: clip}}})
}

Here we pass on arguments to our image URL by grabbing the width and height. We’ve also passed an argument of fit and given it a value of clip to resize the image to fit within the specified parameters without distorting, cropping, or changing the aspect ratio.

Display GraphCMS Data to our Gatsby Client

Use the graphql gatsby export to query the data from the GraphCMS endpoint. On the pages/index.js add the graphql export the gatsby imports.

import { useStaticQuery, graphql } from "gatsby";

At the very bottom define the query:

export default function Gallery() {
  const data = useStaticQuery(graphql`
  query PhotoPage{
    gcms{
        photo{
            id
            name
            description
            image{
                url(transformation: {image: {resize: {width: 500, height: 500, fit: clip}}})
            }
        }
    }
}

const photos = data.gcms.photo;

Open Source Session Replay

OpenReplay is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.

replayer.png

Start enjoying your debugging experience - start using OpenReplay for free.

Building out the application UI

As I stated earlier, we will be using Tailwind CSS for the styling of this application inside the Gallery function code block, add the following code:

return (
  <div className="min-h-screen w-full flex justify-center items-center my-20 mx-0">
    <div className="text-xl bg-white w-5/6 my-0 mx-auto max-w-4xl shadow-lg py-11 px-5 rounded-2xl lg:max-w-6xl lg:p-24">
      <header className="flex items-center justify-center flex-col lg:flex-row lg:justify-between">
        <h1 className="text-4xl font-black tracking-tighter">PhotoGallery</h1>
        <form className="mt-2 w-4/5 max-w-xs relative">
          <input 
            type="text"
            placeholder="search images"
            className="border-b-2 mb-2 text-xl outline-none text-gray-400 bg-transparent w-full"
          />
          <img 
            src={search}
            alt="search btn"
            height="20px"
            width="20px"
            className="absolute right-0 top-0 opacity-50 text-gray-400"
          />
        </form>
      </header>
        <div className="md:grid grid-cols-4 mt-12 gap-5">
      {photos.map(photo => (
        <div key={photo.id} className="w-full h-80 relative overflow-hidden rounded-lg transition-shadow duration-35 ease hover:shadow-lg">
          <img 
            src={photo.image.url}
            alt={photo.name}
            className="h-full w-full object-cover"
          />
          <div className="w-full p-7 absolute bg-white bottom-0 text-xs">
            <h3 className="font-bold">{photo.name}</h3>
            <p>{photo.description}</p>
          </div>
        </div>
      ))}
      </div>
    </div>
  </div>
)

The output should be equivalent because of the results of the Gatsby GraphQL query we created:

{
  "data": {
    "gcms": {
      "photo": [
        {
          "id": "ckxcqscq818i00d5256lsafgz",
          "name": "Safe-passage",
          "description": [
            "Unsplash - unknown"
          ]
        },
        {
          "id": "ckxcrasb418oh0d524cldkhz1",
          "name": "Vercel cup",
          "description": [
            "Unsplash - Kevin-canlas"
          ]
        },
        {
          "id": "ckxcrg4fs193k0b61yu121wp4",
          "name": "Black bitcoin coin",
          "description": [
            "Unsplash - Executium"
          ]
        },
        {
          "id": "ckxcrjqu819510d57tu4a2dsb",
          "name": "Blue Nike Shoe",
          "description": [
            "Unsplash -  Alexander-rotker"
          ]
        },
        {
          "id": "ckxcs7fgo19cz0d57ozjdlio1",
          "name": "Fried Potatoes",
          "description": [
            "Pexels - Dzenina Lukac"
          ]
        },
        {
          "id": "ckxcsbsvc19g60j58db5j4m5v",
          "name": "Bird Swiming",
          "description": [
            "Pixabay - Johnny B. Goode"
          ]
        },
        {
          "id": "ckxcsi8co19iq0j58uxb4c6xw",
          "name": "Pink Flower",
          "description": [
            "Pexel - Lisa"
          ]
        },
        {
          "id": "ckxcsneb419jx0d57puw2ikwh",
          "name": "Dog Hunting",
          "description": [
            "Pikwizard- Retriever"
          ]
        },
        {
          "id": "ckxcsr3so19me0j589rbjcf6v",
          "name": "Sea Lion",
          "description": [
            "Pixabay - Kev"
          ]
        }
      ],
      "assets": [
        {
          "imagePhotos": [
            {
              "image": {
                "url": "https://media.graphcms.com/resize=fit:clip/2GPaCYMvRI2j6lByh6p0"
              }
            }
          ]
        },
        {
          "imagePhotos": [
            {
              "image": {
                "url": "https://media.graphcms.com/resize=fit:clip/llrUKVLgRKyt9Q4ygcyd"
              }
            }
          ]
        },
        {
          "imagePhotos": [
            {
              "image": {
                "url": "https://media.graphcms.com/resize=fit:clip/EvbB0oHpQMGYeVkGk0yO"
              }
            }
          ]
        },
        {
          "imagePhotos": [
            {
              "image": {
                "url": "https://media.graphcms.com/resize=fit:clip/RxufeLgNRCmiyZ93xzeu"
              }
            }
          ]
        },
        {
          "imagePhotos": [
            {
              "image": {
                "url": "https://media.graphcms.com/resize=fit:clip/ZdUwUZ5bQGuQmaKnmUUP"
              }
            }
          ]
        },
        {
          "imagePhotos": [
            {
              "image": {
                "url": "https://media.graphcms.com/resize=fit:clip/vfOeohQWSLKzJqveSP4C"
              }
            }
          ]
        },
        {
          "imagePhotos": [
            {
              "image": {
                "url": "https://media.graphcms.com/resize=fit:clip/nXtEvGxjQwiPWamYYSno"
              }
            }
          ]
        },
        {
          "imagePhotos": [
            {
              "image": {
                "url": "https://media.graphcms.com/resize=fit:clip/VN0vYJGQkafa4AnIcFB8"
              }
            }
          ]
        },
        {
          "imagePhotos": [
            {
              "image": {
                "url": "https://media.graphcms.com/resize=fit:clip/sIXBYDLHQJq5IOYP9hI7"
              }
            }
          ]
        }
      ]
    }
  },
}

This is what our app looks like:

The final result!

Conclusion

At the end of this tutorial, we looked at how we can connect the GraphCMS backend to our Gatsby front end and fetch some data using GraphQL. In the process, we created a photo gallery app and model type to build the application. We also changed the roles and permissions that allow us to perform CRUD operations like reading and updating. We created a page that displays the information queried from our GraphCMS endpoint. If you’d like to learn more about what GraphCMS can do, check out its outstanding features on its website.

All code for this article can be found in Github.