You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
title: 'Turning the Static Dynamic with Gatsby + Netlify Functions + Netlify Identity'
date: 2018-12-26
slug: gatsby-static-dynamic
category: tutorial
tags: ['Tech', 'Netlify', 'Gatsby']
description: Gatsby is great for not only static sites but also traditional web applications. You can add authentication and serverless functionality and get up and running incredibly quickly with Netlify - here's how.
Q: What is one thing that Gatsby is capable of doing that might surprise some people? — ctlee
A: Gatsby can be used to build fully dynamic sites, which surprises some people because of it’s label as a “static site generator”. It’s fully equipped to be a powerful alternative to create-react-app and other similar solutions with the addition of easy pre-rendering and perf baked in. — biscarch
Today I'd like to show you how you can incrementally add functionality to a Gatsby static site with Netlify Functions, and then add authentication with Netlify Identity to begin a proper Gatsby app.
Gatsby's ability to rehydrate (what a delicious word!) the DOM means you can do incredibly dynamic things with JavaScript and React that would be much harder with legacy SSG's.
Let's say you have a typical static Gatsby site, like gatsby-starter-default. You can npm run build it, and it spits out a bunch of HTML files. Great! I can host that for free!
Now your client comes to you and asks you to add some custom logic that needs to be executed on the server:
Maybe you have third party API secrets you don't want to expose to your user.
Maybe you need to ping a database to check your inventory.
Oh no! Now you have to rewrite everything and move to a Digital Ocean droplet!
I'm kidding. No, you don't have to rewrite everything.
The beauty of serverless functions is that it is incrementally adoptable - your site grows with your needs - and with Gatsby you can rerender entire sections of your site based on live API data. Of course, the more you do this, the more resource intensive (in terms of bandwidth and computation) it can be, so there is a performance tradeoff. Your site should be as dynamic as you need it to be, but no more. Gatsby is perfect for this.
5 Steps to add Netlify Functions to Gatsby
Netlify Functions are a great low configuration solution for adding serverless functionality to your Gatsby site. You get 125,000 free calls a month - that's a function call every 20 seconds every day of the week, month, and year - and you can emulate them in local development with netlify-lambda.
Configure your Netlify build: When serving your site on Netlify, netlify-lambda will now build each JavaScript/TypeScript file in your src/lambda folder as a standalone Netlify function (with a path corresponding to the filename). Make sure you have a Functions path in a netlify.toml file at root of your repository:
[build]
Command = "npm run build"Functions = "lambda"Publish = "public"
For more info or configuration options (e.g. in different branches and build environments), check the Netlify.toml reference.
Proxy the emulated functions for local development: Head to gatsby-config.js and add this to your module.exports:
varproxy=require('http-proxy-middleware')module.exports={// for avoiding CORS while developing Netlify Functions locally// read more: https://www.gatsbyjs.org/docs/api-proxy/#advanced-proxyingdevelopMiddleware: app=>{app.use('/.netlify/functions/',proxy({target: 'http://localhost:9000',pathRewrite: {'/.netlify/functions/': ''}}))}// ...}
Write your functions: Make a src/lambda folder and write as many functions as you need. The only requirement is that each function must export a handler, although netlify-lambda helps you use webpack to bundle modules or you can zip the functions yourself. For example you can write src/lambda/hello.js:
// For more info, check https://www.netlify.com/docs/functions/#javascript-lambda-functionsexportfunctionhandler(event,context,callback){console.log('queryStringParameters',event.queryStringParameters)callback(null,{// return null to show no errorsstatusCode: 200,// http status codebody: JSON.stringify({msg: 'Hello, World! '+Math.round(Math.random()*10)})})}
Now you are ready to access this API from anywhere in your Gatsby app! For example, in any event handler or lifecycle method, insert:
and watch "Hello World!" pop up in your console. (I added a random number as well to show the endpoint is dynamic) If you are new to React, I highly recommend reading through the React docs to understand where and how to insert event handlers so you can, for example, respond to a button click.
The local proxying we are doing is only for local emulation, eg it is actually running from http://localhost:9000/hello despite you hitting /.netlify/functions/hello in your Gatsby app. When you deploy your site to Netlify (either by hooking your site up through Git through our Web UI, or our l33t new CLI), that falls away, and your functions -are- hosted on the same URL and "just works". Pretty neat!
That's cool, but its not an app
So, yes, your site can now be more dynamic than any static site. It can hit any database or API. It runs rings around CORS (by the way, you can also use Netlify Redirects for that). But its not an app app. Yet!
The key thing about web apps (and, let's face it, the key thing users really pay for) is they all have some concept of user, and that brings with it all manner of complication from security to state management to role-based access control. Entire routes need to be guarded by authentication, and sensitive content shielded from Gatsby's static generation. Sometimes there are things you -don't- want Google's spiders to see!
It's a different tier of concern, which makes it hard to write about in the same article as a typical Gatsby tutorial. But we're here to make apps, so let's bring it on!
5 Steps to add Netlify Identity and Authenticated Pages to Gatsby
Enable Netlify Identity: Netlify Identity doesn't come enabled by default. You'll have to head to your site admin (eg https://app.netlify.com/sites/YOUR_AWESOME_SITE/identity) to turn it on. Read the docs for further info on what you can do, for example add Facebook or Google social sign-on!
module.exports={plugins: [{resolve: `gatsby-plugin-create-client-paths`,options: {prefixes: [`/app/*`]}}// ...]// ... (including what you also wrote earlier)}
Write an authentication service: netlify-identity-widget is a framework-agnostic overlay that ships with a nice signup/login UI. This gets you up and running the fastest, however if you need a smaller solution you may want to use the underlying gotrue-js, or react-netlify-identity for a React Hooks solution.
Here's a usable example that stores your user in local storage:
importnetlifyIdentityfrom'netlify-identity-widget'exportconstisBrowser=()=>typeofwindow!=='undefined'exportconstinitAuth=()=>{if(isBrowser()){window.netlifyIdentity=netlifyIdentity// You must run this once before trying to interact with the widgetnetlifyIdentity.init()}}exportconstgetUser=()=>isBrowser()&&window.localStorage.getItem('netlifyUser')
? JSON.parse(window.localStorage.getItem('netlifyUser'))
: {}constsetUser=user=>window.localStorage.setItem('netlifyUser',JSON.stringify(user))exportconsthandleLogin=callback=>{if(isLoggedIn()){callback(getUser())}else{netlifyIdentity.open()netlifyIdentity.on('login',user=>{setUser(user)callback(user)})}}exportconstisLoggedIn=()=>{if(!isBrowser())returnfalseconstuser=netlifyIdentity.currentUser()return!!user}exportconstlogout=callback=>{netlifyIdentity.logout()netlifyIdentity.on('logout',()=>{setUser({})callback()})}
Write your app: Now, any sub paths in src/pages/app will be exempt from Gatsby static generation. To keep the dividing line between app and site crystal clear, I like to have all my dynamic Gatsby code in a dedicated app folder. This means you can use @reach/router with netlify-identity-widget to write a standard dynamic React app. Here's some sample code to give you an idea of how to hook them up:
importReactfrom'react'import{Router}from'@reach/router'// comes with gatsby v2importLayoutfrom'../components/layout'importNavBarfrom'./components/NavBar'importProfilefrom'./profile'importMainfrom'./main'// NOT SHOWNimportPrivateRoutefrom'./components/PrivateRoute'importLoginfrom'./login'// remember everything in /app/* is dynamic now!constApp=()=>{return(<Layout><NavBar/><Router><PrivateRoutepath="/app/profile"component={Profile}/><PublicRoutepath="/app"><PrivateRoutepath="/"component={Main}/><Loginpath="/login"/></PublicRoute></Router></Layout>)}functionPublicRoute(props){return<div>{props.children}</div>}exportdefaultApp
importReactfrom'react'import{Link,navigate}from'gatsby'import{getUser,isLoggedIn,logout}from'../services/auth'exportdefault()=>{constcontent={message: '',login: true}constuser=getUser()if(isLoggedIn()){content.message=`Hello, ${user.user_metadata&&user.user_metadata.full_name}`}else{content.message='You are not logged in'}return(<divstyle={{display: 'flex',flex: '1',justifyContent: 'space-between',borderBottom: '1px solid #d1c1e0',backgroundColor: 'aliceblue'}}><span>{content.message}</span><nav><span>Navigate the app: </span><Linkto="/app/">Main</Link>{` `}<Linkto="/app/profile">Profile</Link>{` `}{isLoggedIn() ? (<ahref="/"onClick={event=>{event.preventDefault()logout(()=>navigate(`/app/login`))}}>
Logout
</a>) : (<Linkto="/app/login">Login</Link>)}</nav></div>)}
importReactfrom'react'import{isLoggedIn}from'../services/auth'import{navigate}from'gatsby'classPrivateRouteextendsReact.Component{componentDidMount=()=>{const{ location }=this.propsif(!isLoggedIn()&&location.pathname!==`/app/login`){// If the user is not logged in, redirect to the login page.navigate(`/app/login`)returnnull}}render(){const{component: Component, location, ...rest}=this.propsreturnisLoggedIn() ? <Component{...rest}/> : null}}exportdefaultPrivateRoute
Phew that was a lot! but you should have a solid starting point for your app :)
Bonus points: Authenticated Lambda Functions for your Gatsby App
Just like every magic act has a pledge, a turn, and a prestige, I have one last tidbit for you. Nothing on the client-side is safe, and although you can send along Netlify Identity user id's to your Netlify Function endpoints for authenticated access from your Gatsby App (for example in the body of a POST request), you'll never be truly sure if that flow is secure either from malicious users or snooping.
The best way to do authenticated actions inside serverless functions is to do it from inside the context of the function itself. Fortunately, Netlify Identity and Functions work seamlessly together. All you have to do is to send along the user's JWT when hitting your endpoint:
// in your gatsby appconstuser=getUser()fetch('/.netlify/functions/auth-hello',{headers: {Accept: 'application/json','Content-Type': 'application/json',Authorization: 'Bearer '+user.token.access_token// like this}}).then(/* etc */)
And then inside a Lambda function, you can now access the user object:
// more info: https://www.netlify.com/docs/functions/#identity-and-functions// Note that `netlify-lambda` only locally emulates Netlify Functions, while `netlify-identity-widget` interacts with a real Netlify Identity instance. This means that `netlify-lambda` doesn't support Netlify Functions + Netlify Identity integration.exportfunctionhandler(event,context,callback){if(context.clientContext){const{
user // actual user info you can use for your serverless functions}=context.clientContextcallback(null,{statusCode: 200,body: JSON.stringify({msg: 'auth-hello: '+Math.round(Math.random()*10),
user
})})}else{console.log(` Note that netlify-lambda only locally emulates Netlify Functions, while netlify-identity-widget interacts with a real Netlify Identity instance. This means that netlify-lambda doesn't support Netlify Functions + Netlify Identity integration. `)callback(null,{statusCode: 200,body: JSON.stringify({msg:
"auth-hello - no authentication detected. Note that netlify-lambda doesn't locally emulate Netlify Identity."})})}}
Gatsby - Perfect for your next Hackathon
It's 5 steps each to turn your static Gatsby sites into dynamic, authenticated, fully serverless apps with Netlify's free tools. This makes Gatsby a perfect tool for your next app. If you're at a hackathon, short on time, or just like to see a full working demo, check any of the following links.
title: 'Turning the Static Dynamic with Gatsby + Netlify Functions + Netlify Identity'
date: 2018-12-26
slug: gatsby-static-dynamic
category: tutorial
tags: ['Tech', 'Netlify', 'Gatsby']
description: Gatsby is great for not only static sites but also traditional web applications. You can add authentication and serverless functionality and get up and running incredibly quickly with Netlify - here's how.
In a recent Reactiflux interview, the Gatsby team was asked this question:
Even though Dustin recently wrote about Gatsby for Apps and open sourced his Gatsby Mail demo, I do still find people constantly having to explain that Gatsby is "not just for sites".
Today I'd like to show you how you can incrementally add functionality to a Gatsby static site with Netlify Functions, and then add authentication with Netlify Identity to begin a proper Gatsby app.
Static-Dynamic is a spectrum
Why would you use something like Gatsby over Jekyll or Hugo or one of the hundreds of Static Site Generators out there? There are many reasons, but one of the unique selling points is how Gatsby helps you build "Static Progressive Web Apps" with React.
Gatsby's ability to rehydrate (what a delicious word!) the DOM means you can do incredibly dynamic things with JavaScript and React that would be much harder with legacy SSG's.
Let's say you have a typical static Gatsby site, like gatsby-starter-default. You can
npm run build
it, and it spits out a bunch of HTML files. Great! I can host that for free!Now your client comes to you and asks you to add some custom logic that needs to be executed on the server:
Oh no! Now you have to rewrite everything and move to a Digital Ocean droplet!
I'm kidding. No, you don't have to rewrite everything.
The beauty of serverless functions is that it is incrementally adoptable - your site grows with your needs - and with Gatsby you can rerender entire sections of your site based on live API data. Of course, the more you do this, the more resource intensive (in terms of bandwidth and computation) it can be, so there is a performance tradeoff. Your site should be as dynamic as you need it to be, but no more. Gatsby is perfect for this.
5 Steps to add Netlify Functions to Gatsby
Netlify Functions are a great low configuration solution for adding serverless functionality to your Gatsby site. You get 125,000 free calls a month - that's a function call every 20 seconds every day of the week, month, and year - and you can emulate them in local development with
netlify-lambda
.Let's walk through the steps:
npm install -D http-proxy-middleware netlify-lambda npm-run-all
scripts
inpackage.json
:netlify-lambda
will now build each JavaScript/TypeScript file in yoursrc/lambda
folder as a standalone Netlify function (with a path corresponding to the filename). Make sure you have a Functions path in anetlify.toml
file at root of your repository:For more info or configuration options (e.g. in different branches and build environments), check the Netlify.toml reference.
gatsby-config.js
and add this to yourmodule.exports
:src/lambda
folder and write as many functions as you need. The only requirement is that each function must export ahandler
, althoughnetlify-lambda
helps you use webpack to bundle modules or you can zip the functions yourself. For example you can writesrc/lambda/hello.js
:Now you are ready to access this API from anywhere in your Gatsby app! For example, in any event handler or lifecycle method, insert:
and watch "Hello World!" pop up in your console. (I added a random number as well to show the endpoint is dynamic) If you are new to React, I highly recommend reading through the React docs to understand where and how to insert event handlers so you can, for example, respond to a button click.
The local proxying we are doing is only for local emulation, eg it is actually running from
http://localhost:9000/hello
despite you hitting/.netlify/functions/hello
in your Gatsby app. When you deploy your site to Netlify (either by hooking your site up through Git through our Web UI, or our l33t new CLI), that falls away, and your functions -are- hosted on the same URL and "just works". Pretty neat!That's cool, but its not an app
So, yes, your site can now be more dynamic than any static site. It can hit any database or API. It runs rings around CORS (by the way, you can also use Netlify Redirects for that). But its not an app app. Yet!
The key thing about web apps (and, let's face it, the key thing users really pay for) is they all have some concept of
user
, and that brings with it all manner of complication from security to state management to role-based access control. Entire routes need to be guarded by authentication, and sensitive content shielded from Gatsby's static generation. Sometimes there are things you -don't- want Google's spiders to see!It's a different tier of concern, which makes it hard to write about in the same article as a typical Gatsby tutorial. But we're here to make apps, so let's bring it on!
5 Steps to add Netlify Identity and Authenticated Pages to Gatsby
https://app.netlify.com/sites/YOUR_AWESOME_SITE/identity
) to turn it on. Read the docs for further info on what you can do, for example add Facebook or Google social sign-on!npm install netlify-identity-widget gatsby-plugin-create-client-paths
netlify-identity-widget
is a framework-agnostic overlay that ships with a nice signup/login UI. This gets you up and running the fastest, however if you need a smaller solution you may want to use the underlying gotrue-js, or react-netlify-identity for a React Hooks solution.Here's a usable example that stores your user in local storage:
src/pages/app
will be exempt from Gatsby static generation. To keep the dividing line between app and site crystal clear, I like to have all my dynamic Gatsby code in a dedicatedapp
folder. This means you can use@reach/router
withnetlify-identity-widget
to write a standard dynamic React app. Here's some sample code to give you an idea of how to hook them up:Phew that was a lot! but you should have a solid starting point for your app :)
Bonus points: Authenticated Lambda Functions for your Gatsby App
Just like every magic act has a pledge, a turn, and a prestige, I have one last tidbit for you. Nothing on the client-side is safe, and although you can send along Netlify Identity user id's to your Netlify Function endpoints for authenticated access from your Gatsby App (for example in the body of a POST request), you'll never be truly sure if that flow is secure either from malicious users or snooping.
The best way to do authenticated actions inside serverless functions is to do it from inside the context of the function itself. Fortunately, Netlify Identity and Functions work seamlessly together. All you have to do is to send along the user's JWT when hitting your endpoint:
And then inside a Lambda function, you can now access the
user
object:Gatsby - Perfect for your next Hackathon
It's 5 steps each to turn your static Gatsby sites into dynamic, authenticated, fully serverless apps with Netlify's free tools. This makes Gatsby a perfect tool for your next app. If you're at a hackathon, short on time, or just like to see a full working demo, check any of the following links.
The text was updated successfully, but these errors were encountered: