In the previous blog post we looked at choosing a Netlify framework to architect the Kingston Labs website. In this post I'll be looking at how each of the features were implemented using Netlify with Gatsby.
Delivering Features
The Kingston Labs website has a small set of features that made it ideal for testing out in Netlify, specifically these were:
- A few CMS-able landing pages
- A blog
- A contact form that saves the form submission to a database and sends an email to us
Landing Pages & CMS
The existing Django site fetched content for each landing page (the homepage, about us and portfolio) from standard Django models, for example a CaseStudy
model stored the text and image for each of the case studies on the portfolio page.
On the JAMstack, this functionality can be achieved using one of Netlify's wide range of Headless CMSs. For this project I looked into the following:
- Netlify CMS: stores content in your git repo, using netlify identity to authenticate users
- Prismic: third party service with GraphQL and RESTful APIs
- StoryBlok: third party service with a visual editor
- Strapi: open-source self-hosted project with GraphQL and RESTful APIs
Each of these look great for different use cases — being open source, Strapi would be my natural choice, however, it is not provided as a service, so it would add some expense and development time to such a small project. On the other hand, both Prismic and StoryBlok provide a free tier for a single user so would be a great choice. Ultimately I decided to use Netlify CMS as I felt keeping the content in the same repository as the code would simplify development.
Implementing Netlify CMS
Netlify CMS was easy to set up using the Gatsby Netlify CMS Starter Template. The data structure for each page is defined in config.yml
and allows complex field definitions with widgets (including a rich markdown editor), validation rules and nested fields.
The UI includes a preview of your page which you have to set up by registering a preview template. This was all included in the Gatsby starter template so it was easy to get up and running. The template project even included a solution to an issue with loading images into the preview — a PreviewCompatibleImage
component.
Following this experience using Netlify CMS, I realise that keeping the content in the same repository as the code is not without its drawbacks. Since the content is fetched from a branch of the git repository, it can be quite difficult to test out new data structures — a local testing mode would make this a lot easier to work with.
At the same time, although keeping the content and code in the same place is great for ensuring data consistency, it does lead to quite a messy git history when content editors are effectively pushing to your codebase.
A separate content manager like Prismic or StoryBlok would likely be better for scalability, especially if you have a large archive of articles and many different users and roles. In addition, these also include deploy hooks so that your site can be rebuilt with the new changes immediately or at the end of the day if you want to keep your build hours in check. This could also be really useful for publishing pages at a certain date in the future.
Blog
The most important feature of the Blog is the same as that of the landing pages, a CMS, but in addition to content editing, the blog also requires a listing page.
This was really easy to do using Django's Class Based Views alongside a BlogPost
model. Thankfully this is also really easy with Gatsby — the Netlify CMS starter includes a good implementation that is easy to understand.
Here, an index.js
file includes a GraphQL query to fetch all of the relevant articles which can then be rendered using a React component. Another great feature that is included in the template project is tagged pages — tags can be added to an article in the CMS, with tag pages listing all the articles with a given tag. This is achieved in the gatsby-node.js
file using the createPage function for each of the tags. Pagination can also be added manually or using a package like Gatsby-Paginate.
Search
Looking to the future, a search box would be really useful — this would have been very easy to implement using model filtering in Django (although of course a proper search engine should be used if there were a very high number of articles).
This is one area where Netlify is not quite so simple. Since a search page is dynamic by nature, pre-building static pages is not an effective solution. There are a few options available to solve this though.
Firstly, algolia is a fully-featured search engine that integrates well with Gatsby as explained in the Gatsby Docs. A free community package is available, but the pricing for commercial projects starts at $29 a month, making this quite expensive for a small site such as this one.
Serverless Functions
Alternatively, this is a really good use-case for Netlify's serverless Lambda Functions. An example for these is also included in the template starter project. Simply put, Lambda functions are a piece of code that you can call as an API. Currently Netlify supports functions written in both JavaScript and Go.
Netlify provides 125,000 free requests per month or 100 hours, which should be enough for a small project, but paid plans are also available that provide many more hours worth of requests.
Functions are perfect when you need to make a static page dynamic. Since each serverless function is run by Netlify and not the client, we can use secret API keys and tokens in the request — this means we could contact one of the CMS services to search the articles (both Prismic and StoryBlok provide full text search).
Adding search to Netlify CMS may prove to be a little more difficult but the Lunr search engine with the Gatsby plugin may be a good option.
Contact Form
The last feature needed on the website is a contact form — this was previously implemented using a Django ModelForm
to save enquiries to our database and forward that message on to a Kingston Labs email account. This feature turned out to be extremely easy to implement using Netlify Forms.
At its simplest, all you need to do is set a Netlify data attribute on the form, but it is also easy to set up a success page, reCaptcha challenges or JavaScript submissions.
<form name="contact" method="POST" data-netlify="true">
<label for="email">Email</label>
<input type="email" name="email"/>
<label for="message">Message</label>
<textarea name="message"></textarea>
<button type="submit">Send</button>
</form>
Form validation needs to be carried out client-side using HTML and / or JavaScript validation. More complex server side validations (for example, to validate unique email addresses) would be really simple using a server-side framework like Django, but do not appear to be provided by Netlify.
I understand that the third party forms service kwes provides server-side validation, so this would be useful to investigate for more complicated forms. Alternatively, you could build your own API which could be used to validate and store your data.
Netlify's free tier offers 100 submissions per month (with 10MB of uploads) and for $19 per month you can get 1,000 submissions (and 1GB uploads). This is reasonable for fairly small sites, but it would make sense to set up your own service or something like kwes or Google Forms if you are expecting a larger number of form submissions.
Notification Hooks & Zapier
Once the form is submitted, Netlify saves the data, however there is no way of knowing that a new form has been submitted without going into Netlify and checking. What we really need is an email notification.
Netlify allows you to configure email notifications, Slack integrations or your own custom web hooks. Sending email notifications was as easy as specifying an email address in the Netlify configuration.
Since this was so easy, I also decided to save the form submissions in a Google Sheet using Zapier. This is an amazing tool that works by connecting different apps together through Zaps. These let you set up triggers and actions, so in this case a Netlify form submission triggered an action to save the form submission in a Google Sheet.
After a little time configuring the form fields this proved to work extremely well, effectively operating as a simple database and reporting backend (it even captures the User Agent and Timestamp).
Zapier integrates with a huge range of applications so I am expecting it to be a really important part of implementing successful JAM projects — it can even be used to perform scheduled tasks (like a CRON job) which could be useful for rebuilding sites on a regular basis.
Extras
With all the key features of the website implemented, it's worth pointing out a few of the other features that Netlify and Gatsby offer.
- SSL (HTTPS) is provided for free along with DNS management, in fact you can even buy your own domains in the same place
- Continuous integration and deployments automate tests and let you trial any new features before making them live — branch-based split testing is also available
- Gatsby plugins make it easy to add additional features such as Google Analytics or Disqus Comments
Conclusion
After some initial scepticism I am now fully bought into the whole concept of JAMstack — it provides far more than just a static site generator thanks to Netlify's powerful integrations with serverless functions and web hooks.
Headless CMSs make content management simpler than ever, whilst other APIs such as SnipCart are available for e-commerce projects.
There are so many strengths inherent to the architecture, such as faster page loads, speedier development, improved security and minimal need for maintenance. However there are limitations that need to be considered before implementing a project including:
-
Scalability: JAMstack is superb in terms of scaling traffic since it serves all its content over a CDN, however, there are potentially some issues if you have a very large amount of content. Imagine a large site like BBC News which contains a lot of historical and archived articles. In this case it would take a huge amount of time to rebuild every old article. Many times, the article probably wouldn't have been requested in between deploys so it would be more efficient to build it when the request comes in. Given some thought, I expect there are good solutions to this, for example, you could flag that certain pages should not be rebuilt when a new deploy is triggered.
-
User-contributed content: sites with a large amount of user content would need to be rebuilt rapidly to keep up to date. One of the most common use-cases here are user-comments. The JAMstack architecture does still work here quite well by deferring these to a external services such as Disqus. However, for more complex applications, it would make a lot of sense to build out an API in a more traditional server-side framework like Django with Django Rest Framework for a REST API or Graphene for a GraphQL API — these could then be called from a Lambda Function in Netlify.
-
Costs and limits: Netlify is incredibly cost-effective for smaller sites and will often result in no costs whatsoever. However, higher-traffic sites will start hitting some of the limits on function calls and form submissions so it is important to monitor these.
Overall Netlify is a great choice for the vast majority of projects, and whilst you may need to reconsider some of the most common web-paradigms, I believe the benefits far outweigh the costs. If you have any questions or would like to tell us about your experiences with Netlify and Gatsby, please add a comment below.