Tutorial: A Gatsby Photo Blog Powered by Flickr
Rose
Posted on June 16, 2020
š¤ What this tutorial covers
- Setting up a paginated feed of photos in Gatsby, sourced from Flickr
- You can see the finished project here and You can see its source code here
š āāļø What this tutorial does NOT cover
- Making it look nice
- Handling rebuilds when new photos are added to Flickr
- Optimizations such as using environment variables for Flickr API key, "load-up" of images for better performance, or any other nice-to-have you can think of. This is bare-bones. The expectation is that you'd use this tutorial to get started, then tidy it up and make it exactly how you want it š
š¤Æ Huh what who? Where am I?
Gatsby is a very popular framework for building static websites. I chose it for this tutorial because of its popularity. Popular frameworks = more resources to learn from and available plugins to use. And this tutorial will provide more value if it's something many people use!
Flickr is a photo hosting product. I chose it because I have nostalgic fondness for Flickr and they do allow you to embed their photos, as long as you follow their terms.
š§ Are you an expert?
NO! I am a JavaScript developer and I do know React, but otherwise all the technologies in this tutorial are pretty new to me.
I built out this project over a couple of hours. I've dabbled in Gatsby but don't really know it all that well. Same goes for GraphQL. I've never used the Flickr API before. So if I can fumble my way through this and then live to write a tutorial, so can you š
š„³ OK let's get started.
You're going to need a few things right off the bat:
- You'll need to sign up for an account on Flickr (free plan available)
- You'll then need to get your own Flickr API key
- You'll want to make sure you have the Gatsby CLI (command line interface) installed
š©āš» Start a new Gatsby Project
Got all that? Ok let's get down to it.
We're going to use the Gatsby CLI to create a new site. I ended up using their basic Hello World starter as my base template, because it really contains the bare minimum.
gatsby new photo-blog https://github.com/gatsbyjs/gatsby-starter-hello-world
We then want to navigate into this directory
cd photo-blog
And now that we're there, we'll want to install gatsby-source-flickr which is what we'll be using to access the Flickr API. And this is the benefit of working with an established framework like Gatsby: Someone else has already done all the heavy lifting for us!
Depending on if you're using yarn or npm you'll add this differently. Here it is if you're using npm:
npm install --save gatsby-source-flickr
Now all we're going to do is follow the setup documentation for gatsby-source-flickr
. We need to open gatsby-config.js
and configure our Flickr API key as well as the user ID on Flickr we want to get the photos from. gatsby-config.js
should look something like this now:
module.exports = {
plugins: [
{
resolve: "gatsby-source-flickr",
options: {
api_key: "INSERT YOUR FLICKR API KEY HERE",
user_id: "INSERT YOUR FLICKR USEER ID HERE"
}
}
],
}
šāāļø Hot tip: Once you have everything working as a proof-of-concept, if you want to use this in real life I'd advise looking into environment variables for these values, instead of saving these values directly in the config file.
āNeed help finding your API key? You should have been given it after initial set up, but if you need to go back and find it, you can go to the app garden on Flickr and click the link that says "Apps by you" on the right hand side.
ā Need help finding your user ID? If you navigate to your photo stream and look at the URL bar, the URL looks something like this: https://www.flickr.com/photos/USERIDHERE
. Grab that last value after /photos/
!
Now we can run
gatsby develop
and then use our browser to navigate to http://localhost:8000/___graphql. I love this view because it gives you an overview of all the data available to you. Once Flickr is properly configured, it means we can play around and see what kind of information we can fetch from the Flickr API!
For a feed of multiple photos, the interesting data is in allFlickrPhoto
You can click around to see what kind of data is available there and then decide what you need. Or you can just keep reading to see what I ended up using š
āļø Let's set up some pages!
Gatsby has a tutorial on adding pagination which is a good starting point. It's not Flickr-specific though, of course, so some tweaks need to be made. I also found this tutorial useful for the previous/next links in pagination.
Open up gatsby-node.js
This is where we'll define all our page paths.
We need to know how many pages to generate. To do this we can query Flickr with our "number of photos per page" (aka 'limit') and then get the pageInfo
which contains a handy page count.
query {
allFlickrPhoto(limit: 10) {
pageInfo {
pageCount
currentPage
}
}
}
Once we know how many pages there are, we can loop between 0 and totalPages and generate a path for each page. In the end, gatsby-node.js
should look like this:
const path = require('path');
const postsPerPage = 5; // change this value if you want a different number of posts per page.
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions;
const result = await graphql(
`
query($limit: Int!) {
allFlickrPhoto(limit: $limit, filter: {media: {eq: "photo"}}) {
pageInfo {
pageCount
currentPage
}
}
}
`
, {limit: postsPerPage});
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`);
return;
}
const numPages = result.data.allFlickrPhoto.pageInfo.pageCount;
Array.from({length: numPages}).forEach((_, i) => {
createPage({
path: i === 0 ? `/` : `/${i + 1}`,
component: path.resolve('./src/templates/flickr-photo-list-template.js'),
context: {
limit: postsPerPage,
skip: i * postsPerPage,
numPages,
currentPage: i + 1,
},
});
});
}
You'll noticed that I moved limit
into a variable to make it easier to change and have that change cascade nicely.
I also added a "filter" param so that we're only getting photos, not videos and other media.
Next up we need to set up './src/templates/flickr-photo-list-template.js'
, which is referenced here but doesn't actually exist yet.
š§āāļø Create that file in the appropriate directory.
š® You can also delete pages/index.js
if you're following this tutorial, as I set the route of /
to be page one of the Flickr photo list, so we don't need a default index page.
On this flickr-photo-list-template.js
template we'll define the basic rendering of the data, as well as a GraphQL query for getting the information from Flickr we need in order to render that data.
The query will look something like this. "Skip" is for pagination (If you are having 5 photos per page and you are on page 2, skip would be "5". Page 3, skip would be "10" etc. This value was passed in when we set up gatsby-node.js
, go check it out if you missed it.)
query ($skip: Int!, $limit: Int!) {
allFlickrPhoto(limit:$limit, skip: $skip, sort: { order: DESC, fields: [dateupload_date] }, filter: {media: {eq: "photo"}}) {
edges {
node {
id
title
url_m
description
photo_id
}
}
}
}
Then we can use the data we receive to render each individual photo by looping through them via map
-
render() {
// get photos from response
const photos = this.props.data.allFlickrPhoto.edges;
// call `renderPhoto` method for each photo via map
return (
<div>
{photos.map(renderPhoto)}
</div>
);
}
renderPhoto
looks at an individual object in the array of results and displays its title, image, and description. You can tweak this to your heart's desire, and if you need different attributes, you can update your GraphQL query and then reference it here -
function renderPhoto(item) {
let photo = item.node;
let flickrPhotoURL = `https://www.flickr.com/photos/[YOUR FLICKR USER ID HERE]/${photo.photo_id}`;
return (
<div key={photo.id}>
<h1>{photo.title}</h1>
<a href={flickrPhotoURL}>
<img src={photo.url_m} alt={photo.title} />
</a>
<p>{photo.description}</p>
<p>
<a href={flickrPhotoURL}>View on Flickr</a>
</p>
</div>
);
}
Add some pagination information and the entire file looks like this:
import React from 'react';
import { graphql, Link } from 'gatsby';
function renderPhoto(item) {
let photo = item.node;
let flickrPhotoURL = `https://www.flickr.com/photos/[YOUR FLICKR USER ID HERE]/${photo.photo_id}`;
return (
<div key={photo.id}>
<h1>{photo.title}</h1>
<a href={flickrPhotoURL}>
<img src={photo.url_m} alt={photo.title} />
</a>
<p>{photo.description}</p>
<p>
<a href={flickrPhotoURL}>View on Flickr</a>
</p>
</div>
);
}
export default class PhotoList extends React.Component {
renderPagination() {
const { currentPage, numPages } = this.props.pageContext;
const isFirst = currentPage === 1;
const isLast = currentPage === numPages;
const prevPage = currentPage - 1 === 1 ? "/" : (currentPage - 1).toString();
const nextPage = (currentPage + 1).toString();
return (
<div>
{!isFirst && (
<Link to={prevPage} rel="prev">
ā Previous Page
</Link>
)}
{!isLast && (
<Link to={nextPage} rel="next">
Next Page ā
</Link>
)}
</div>
);
}
render() {
const photos = this.props.data.allFlickrPhoto.edges;
return (
<div>
{photos.map(renderPhoto)}
Page {this.props.pageContext.currentPage} of {this.props.pageContext.numPages}
{this.renderPagination()}
</div>
);
}
}
export const photoListQuery = graphql`
query ($skip: Int!, $limit: Int!) {
allFlickrPhoto(limit:$limit, skip: $skip, sort: { order: DESC, fields: [dateupload_date] }, filter: {media: {eq: "photo"}}) {
edges {
node {
id
title
url_m
description
photo_id
}
}
}
}
`
If you now navigate to http://localhost:8000 you should see a feed of your photos. You have successfully set up a very basic Flickr powered photo blog! š
It's up to you where you take it from here š And thanks very much for sticking with me for this long!
āļøI already mentioned this at the beginning but I think it is worth re-iterating: If you set this up and run gatsby build
to have this running in the wild... And then add photos to Flickr, it will not dynamically update whenever you upload a new photo. It is a static site. You'll need some kind of re-build process to handle this. You could check Flickr's documentation to see if Flickr has any kind of 'new photo' webhook and use it to trigger a re-build, for example.
š¤ Hopefully you found this useful and informative. Comment and let me know if there's any areas you think could be explained more thoroughly and I may tweak this post for future readers.
Posted on June 16, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.