To make the move from “site” to app, we’ll need to dive into the world
of “app-generated” content. In this article, we’ll get started in this
world with the power of serverless data. We’ll start with a simple demo
by ingesting and posting data to FaunaDB
and then extend that functionality in a full-fledged application using
Auth0, FaunaDB’s Token system and User-Defined Functions.
The JAMstack has proven itself to be one of the top ways of producing content-driven sites, but it’s also a great place to house applications, as well. If you’ve been using the JAMstack for your performant websites, the demos in this article will help you extend those philosophies to applications as well.
When using the JAMstack to build applications, you need a data service that fits into the most important aspects of the JAMstack philosophy:
These are great services that can do a lot of the low-level work of many applications, but once your data is more complex than a spreadsheet or needs to be updated and store in real-time, it might be time to look into a database.
The service API can still be in use, but a central database managing the state and operations of your app becomes much more important. Even if you need a database, you still want it to follow the core JAMstack philosophies we outlined above. That means, we don’t want to host our own database server. We need a Database-as-a-Service solution. Our database needs to be optimized for the JAMstack:
Let’s dive into the code!
In this demo, we’ll create an application that was all the rage in that time period: the guestbook. A guestbook is nothing but app-generated content and interaction. A user can come to the site, see all the signatures of past “guests” and then leave their own.
To start, we’ll statically render our site and build our data from Fauna during our build step. This will provide the fast performance we expect from a JAMstack site. To do this, we’ll use GatsbyJS.
Gatsby comes with a large repository of starters that can help bootstrap your project. For this demo, I chose a simple starter that came equipped with the Bulma CSS framework.
This gives us a good starting point and structure. It also has the added benefit of coming with styles that are ready to go.
Let’s do a little cleanup for things we don’t need. We’ll start by simplifying our
This will get rid of much of the branded content. Feel free to customize this section, but we won’t write any of our code here.
Next we’ll clean out the
In this code, we’ve mostly removed the “site” content and added in a couple new components. A
Now that we have a relatively blank slate, we can set up our FaunaDB database.
Inside this database, we’ll create a “Collection” called
In this new Collection, we’ll create a new Document with the following JSON:
This
will be the simple data schema for each of our signatures. For each of
these Documents, Fauna will create additional data surrounding it.
The
After creating our data, we want an easy way to grab all that data and use it in our site. In Fauna, the most efficient way to get data is via an Index. We’ll create an Index called
Now that we have an efficient way of accessing the data in Gatsby, we need Gatsby to know where to get it. Gatsby has a repository of plugins that can fetch data from a variety of sources, Fauna included.
We can then head over to the “Security” tab in our Database and create a new key. Since this is a protected secret, it’s safe to use a “Server” role. When you save the Key, it’ll provide your secret. Be sure to grab that now, as you can’t get it again (without recreating the Key).
Once the configuration is set up, we can write a GraphQL query in our components to grab the data at build time.
This will access the
We’ll set that data into our state — this will make updating it live easier later.
Now we can pass
Let’s set up our Signatures component to use that data!
In this function, we’ll
The
At
this point, if you start your Gatsby development server, you should
have a list of signatures currently existing in your database. Run the
following command to get up and running:
Any signature stored in our database will build HTML in that component. But how can we get signatures INTO our database?
Let’s set up a signature form component to send data and update our Signatures list.
To
start, we’ll set up our state to include the name and the message.
We’ll default them to blank strings and insert them into our
When a user changes the value of one of these fields, we’ll use the
Let’s break down both of those functions.
The input change will accept the event. From that event, it will get the current target’s value and name. We can then modify the state of the properties on our state object — sigName, sigMessage or anything else.
Once the state has changed, we can use the state in our
This function will call a new
The
In order to write to our database, we’ll need to set up a new key in Fauna with minimal permissions. Our server key is allowed higher permissions because it’s only used during build and won’t be visible in our source.
This key needs to only allow for the ability to only create new items in our
Note: A user could still be malicious with this key, but they can only do as much damage as a bot submitting that form, so it’s a trade-off I’m willing to make for this app.
For this, we’ll create a new “Role” in the “Security” tab of our dashboard. We can add permissions around one or more of our Collections. In this demo, we only need
After that, we generate a new key that uses that role.
To use this key, we’ll instantiate a new version of the Fauna JavaScript SDK. This is a dependency of the Gatsby plugin we installed, so we already have access to it.
By using an environment variable prefixed with
By importing the
We pass the Create function to the
Next, we pass it the name and message we collected in our state. The response we get back from Fauna is the entire object of our Document. This includes our data in a
Our submit handler will then pass that data into our
From here, we need to tell our JAMstack host to rebuild our site. Many have the ability to specify a webhook to trigger a deployment. Since I’m hosting this demo on Netlify, I can create a new “Deploy webhook” in their admin and create a new
Both
Gatsby Cloud and Netlify
have implemented ways of handling “incremental” builds with Gatsby
drastically speeding up build times. This sort of build can happen very
quickly now and feel almost as fast as a traditional server-rendered
site.
Every signature that gets added gets quick feedback to the user that it’s been submitted, is perpetually stored in a database, and served as HTML via a build process.
Still feels a little too much like a typical website? Let’s take all these concepts a step further.
This app intends to help you focus on one randomized idea every day and review the various ideas from recent days.
To do this, we need to introduce a key element to most apps: authentication. With authentication, comes extra security concerns. While this data won’t be particularly sensitive, you don’t want one user accessing the history of any other user.
Since we’ll be scoping data to a specific user, we also don’t want to store any secret keys on browser code, as that would open up other security flaws.
We could create an entire authentication flow using nothing but our wits and a user database with Fauna. That may seem daunting and moves us away from the features we want to write. The great thing is that there’s certainly an API for that in the JAMstack! In this demo, we’ll explore integrating Auth0 with Fauna. We can use the integration in many ways.
The typical flow would be to send a login request to a serverless function. That function would request a user from Auth0. Auth0 would provide the user’s JSON Web Token (JWT) and the function would provide any additional information about the user our application needs. The function would then bundle everything up and send it to the browser.
There are a lot of places in that authentication flow where a developer could introduce a security hole.
Instead, let’s request that Auth0 bundle everything up for us inside the JWT it sends. Keeping security in the hands of the folks who know it best.
We’ll do this by using Auth0’s Rules functionality to ask Fauna for a user token to encode into our JWT. This means that unlike our Guestbook, we won’t have any Fauna keys in our front-end code. Everything will be managed in memory from that JWT token.
Following the configuration steps in their basic walkthrough gets the important basic information filled in. Be sure to fill out the proper localhost port for your bundler of choice as one of your authorized domains.
After the basics of the application are set up, we’ll go into the “Rules” section of our account.
Click “Create Rule” and select “Empty Rule” (or start from one of their many templates that are helpful starting points).
Here’s our Rule code
We
give the rule a function that takes the user, context, and a callback
from Auth0. We need to set up and grab a Server token to initialize our
Fauna JavaScript SDK and initialize our client. Just like in our
Guestbook, we’ll create a new Database and manage our Tokens in
“Security”.
From there, we want to send a query to Fauna to create or log in our user. To keep our Rule code simple (and make it reusable), we’ll write our first Fauna “User-Defined Function” (UDF). A UDF is a function written in FQL that runs on Fauna’s infrastructure.
First, we’ll set up a Collection for our users. You don’t need to make a first Document here, as they’ll be created behind the scenes by our Auth0 rule whenever a new Auth0 user is created.
Next, we need an Index to search our
It’s time to create our UDF. In the Dashboard, navigate to “Functions” and create a new one named
Our UDF will accept a user email address and the rest of the user information. If a user exists in a
We can then store the Token as an
This Token doesn’t have any permissions yet. We need to go into our Security rules and set up a new Role.
We’ll create an “AuthedUser” role. We don’t need to add any permissions yet, but as we create new UDFs and new Collections, we’ll update the permissions here. Instead of generating a new Key to use this Role, we want to add to this Role’s “Memberships”. On the Memberships screen, you can select a Collection to add as a member. The documents in this Collection (in our case, our Users), will have the permissions set on this role given via their Token.
Now, when a user logs in via Auth0, they’ll be returned a Token that matches their user Document and has its permissions.
From here, we come back to our application.
First, we’ll need the Auth0 SPA SDK.
First, we configure the SDK with our client_id from Auth0. This is safe information to store in our code.
Next, we set up a function that can be exported and used in multiple files to check if a user is logged in. The Auth0 library provides an
We set up a
Once this is all set up, we have our authentication and user login squared away.
We’ll create a new function for our Fauna functions to reference to get the proper token set up.
This returns a new connection to Fauna using our Token from Auth0. This token works the same as the Keys from previous examples.
From here, we’ll move to our JavaScript and create a function for adding and returning a random item from that Collection.
To start, we’ll instantiate our client with our
From there, we’ll grab all the Documents from our
We’ll pass that Ref to a new UDF that will handle storing a new, timestamped object for that user stored in a new
We’ll create the new Collection, but we’ll have our UDF provide the data for it when called.
We’ll create a new UDF in the Fauna dashboard with the name
As with our login UDF before, we’ll use the
Without passing any user information to the function, FQL is able to obtain our User Ref just calling the
We then return the
The first rule of Serverless Data Club is not to make HTTP requests unless you have to. In other words, cache when you can. Whether that’s creating a full PWA-scale application with Service Workers or just caching your database response with localStorage, cache data, and fetch only when necessary.
The first rule of our conditional is to check localStorage. If localStorage does contain a
The second rule of Serverless Data Club is to make as few requests as possible without the responses of those requests being too large. In that vein, our second conditional rule is to check the latest item from the current user and see if it is from today. If it is, we’ll store it in localStorage for later and then render the results.
Finally, if none of these are true, we’ll fire our
Our new UDF is going to call a Fauna Index. An Index is an efficient way of doing a lookup on a Fauna database. In our case, we want to return all
Simple Indexes can be created in the Index dashboard. Since we want to do the reverse sort, we’ll need to enter some custom FQL into the Fauna Shell (you can do this in the database dashboard Shell section).
This creates an Index named
We’ll create a new UDF to use this Index.
This time our
First, we’ll check to see if there’s at least 1 item in our Index. If there is, we’ll grab the first item’s data and time and return that back as a merged object.
After we get the latest from Fauna in our JavaScript, we’ll format it to a structure our
Now, we have an application that creates, stores, and fetches data for a daily message to contemplate. A user can use this on their phone, on their tablet, on the computer, and have it all synced. We could turn this into a PWA or even a native app with a system like Ionic.
We’re still missing one feature. Viewing a certain number of past items. Since we’ve stored this in our database, we can retrieve them in whatever way we need to.
Our UDF will be very similar to the
In
this demo, we created a full-fledged app with serverless data. Because
the data is served from a CDN, it can be as close to a user as possible.
We used
FaunaDB’s features, such
as UDFs and Indexes, to optimize our database queries for speed and ease
of use. We also made sure we only queried our database the bare minimum
to reduce requests.
With performance on the mind of everyone creating on the JAMstack — whether for cost or for user experience — finding a good place to store and retrieve your data is a high priority. Find a spot that meets your needs, those of your users, and meets ideals of the JAMstack.
The JAMstack has proven itself to be one of the top ways of producing content-driven sites, but it’s also a great place to house applications, as well. If you’ve been using the JAMstack for your performant websites, the demos in this article will help you extend those philosophies to applications as well.
When using the JAMstack to build applications, you need a data service that fits into the most important aspects of the JAMstack philosophy:
- Global distribution
- Zero operational needs
- A developer-friendly API.
These are great services that can do a lot of the low-level work of many applications, but once your data is more complex than a spreadsheet or needs to be updated and store in real-time, it might be time to look into a database.
The service API can still be in use, but a central database managing the state and operations of your app becomes much more important. Even if you need a database, you still want it to follow the core JAMstack philosophies we outlined above. That means, we don’t want to host our own database server. We need a Database-as-a-Service solution. Our database needs to be optimized for the JAMstack:
- Optimized for API calls from a browser or build process.
- Flexible to model your data in the specific ways your app needs.
- Global distribution of our data like a CDN houses our sites.
- Hands-free scaling with no need of a database administrator or developer intervention.
Let’s dive into the code!
A JAMstack Guestbook App With Gatsby And Fauna
I’m a big fan of reimagining the internet tools and concepts of the 1990s and early 2000s. We can take these concepts and make them feel fresh with the new set of tools and interactions.In this demo, we’ll create an application that was all the rage in that time period: the guestbook. A guestbook is nothing but app-generated content and interaction. A user can come to the site, see all the signatures of past “guests” and then leave their own.
To start, we’ll statically render our site and build our data from Fauna during our build step. This will provide the fast performance we expect from a JAMstack site. To do this, we’ll use GatsbyJS.
Initial setup
Our first step will be to install Gatsby globally on our computer. If you’ve never spent much time in the command line, Gatsby’s “part 0” tutorial will help you get up and running. If you already have Node and NPM installed, you’ll install the Gatsby CLI globally and create a new site with it using the following commands:Gatsby comes with a large repository of starters that can help bootstrap your project. For this demo, I chose a simple starter that came equipped with the Bulma CSS framework.
Let’s do a little cleanup for things we don’t need. We’ll start by simplifying our
components.header.js
Next we’ll clean out the
components/midsection.js
file. This will be where our app’s code will render.<SignForm>
that will contain our form for submitting a signature and a <Signatures>
component to contain the list of signatures.Now that we have a relatively blank slate, we can set up our FaunaDB database.
Setting Up A FaunaDB Collection
After logging into Fauna (or signing up for an account), you’ll be given the option to create a new Database. We’ll create a new database calledguestbook
.Inside this database, we’ll create a “Collection” called
signature
. Collections in Fauna a group of Documents that are in turn JSON objects.In this new Collection, we’ll create a new Document with the following JSON:
ref
is the unique identifier inside of Fauna and the ts
is the time (as a Unix timestamp) the document was created/updated.After creating our data, we want an easy way to grab all that data and use it in our site. In Fauna, the most efficient way to get data is via an Index. We’ll create an Index called
allSignatures
. This will grab and return all of our signature Documents in the Collection.Now that we have an efficient way of accessing the data in Gatsby, we need Gatsby to know where to get it. Gatsby has a repository of plugins that can fetch data from a variety of sources, Fauna included.
Setting up the Fauna Gatsby Data Source Plugin
After we install this plugin to our project, we need to configure it in ourgatsby-config.js
file. In the plugins
array of our project, we’ll add a new item.
In
this configuration, you provide it your Fauna secret Key, the Index
name we created and the “type” we want to access in our Gatsby GraphQL
query.
Where did that
In your project, create a process.env.YOUR_FAUNADB_SECRET
come from?.env
file — and include that file in your .gitignore! This file will give
Gatsby’s Webpack configuration the secret value. This will keep your
sensitive information safe and not stored in GitHub.We can then head over to the “Security” tab in our Database and create a new key. Since this is a protected secret, it’s safe to use a “Server” role. When you save the Key, it’ll provide your secret. Be sure to grab that now, as you can’t get it again (without recreating the Key).
Once the configuration is set up, we can write a GraphQL query in our components to grab the data at build time.
Getting the data and building the template
We’ll add this query to our Midsection component to make it accessible by both of our components.This will access the
Signatures
type we created in the configuration. It will grab all the signatures
and provide an array of nodes. Those nodes will contain the data we
specify we need: name
, message
, ts
, id
.We’ll set that data into our state — this will make updating it live easier later.
Now we can pass
sigData
as a prop into <Signatures>
and setSigData
into <SignForm>
.Let’s set up our Signatures component to use that data!
.map()
over our signature data and create an Array of markup based on a new <Signature>
component that we pass the data into.The
Signature
component will handle formatting our data and returning an appropriate set of HTML.Any signature stored in our database will build HTML in that component. But how can we get signatures INTO our database?
Let’s set up a signature form component to send data and update our Signatures list.
Let’s Make Our JAMstack Guestbook Interactive
First, we’ll set up the basic structure for our component. It will render a simple form onto the page with a text input, a textarea, and a button for submission.<textarea>
and <input>
.When a user changes the value of one of these fields, we’ll use the
handleInputChange
method. When a user submits the form, we’ll use the handleSubmit
method.Let’s break down both of those functions.
The input change will accept the event. From that event, it will get the current target’s value and name. We can then modify the state of the properties on our state object — sigName, sigMessage or anything else.
Once the state has changed, we can use the state in our
handleSubmit
method.createSignature()
method. This will connect to Fauna to create a new Document from our state items.The
addSignature()
method will update our Signatures list data with the response we get back from Fauna.In order to write to our database, we’ll need to set up a new key in Fauna with minimal permissions. Our server key is allowed higher permissions because it’s only used during build and won’t be visible in our source.
This key needs to only allow for the ability to only create new items in our
signatures
collection.Note: A user could still be malicious with this key, but they can only do as much damage as a bot submitting that form, so it’s a trade-off I’m willing to make for this app.
For this, we’ll create a new “Role” in the “Security” tab of our dashboard. We can add permissions around one or more of our Collections. In this demo, we only need
signatures
and we can select the “Create” functionality.After that, we generate a new key that uses that role.
To use this key, we’ll instantiate a new version of the Fauna JavaScript SDK. This is a dependency of the Gatsby plugin we installed, so we already have access to it.
GATSBY_
, we gain access to it in our browser JavaScript (be sure to add it to your .env
file).By importing the
query
object from the SDK, we gain access to any of the methods available in
Fauna’s first-party Fauna Query Language (FQL). In this case, we want to
use the Create method to create a new document on our Collection.client.query()
method. Create takes a Collection reference and an object of information to pass to a new Document. In this case, we use q.Collection
and a string of our Collection name to get the reference to the
Collection. The second argument is for our data. You can pass other
items in the object, so we need to tell Fauna, we’re specifically
sending it the data
property on that object.Next, we pass it the name and message we collected in our state. The response we get back from Fauna is the entire object of our Document. This includes our data in a
data
object, as well as a Fauna ID and
timestamp. We reformat that data in a way that our Signatures list can
use and return that back to our handleSubmit
function.Our submit handler will then pass that data into our
setSigData
prop which will notify our Signatures component to rerender with that
new data. This gives our user immediate feedback that their submission
has been accepted.Rebuilding the site
This is all working in the browser, but the data hasn’t been updated in our static application yet.From here, we need to tell our JAMstack host to rebuild our site. Many have the ability to specify a webhook to trigger a deployment. Since I’m hosting this demo on Netlify, I can create a new “Deploy webhook” in their admin and create a new
triggerBuild
function. This function will use the native JavaScript fetch()
method and send a post request to that URL. Netlify will then rebuild the application and pull in the latest signatures.Every signature that gets added gets quick feedback to the user that it’s been submitted, is perpetually stored in a database, and served as HTML via a build process.
Still feels a little too much like a typical website? Let’s take all these concepts a step further.
Create A Mindful App With Auth0, Fauna Identity And Fauna User-Defined Functions (UDF)
Being mindful is an important skill to cultivate. Whether it’s thinking about your relationships, your career, your family, or just going for a walk in nature, it’s important to be mindful of the people and places around you.This app intends to help you focus on one randomized idea every day and review the various ideas from recent days.
To do this, we need to introduce a key element to most apps: authentication. With authentication, comes extra security concerns. While this data won’t be particularly sensitive, you don’t want one user accessing the history of any other user.
Since we’ll be scoping data to a specific user, we also don’t want to store any secret keys on browser code, as that would open up other security flaws.
We could create an entire authentication flow using nothing but our wits and a user database with Fauna. That may seem daunting and moves us away from the features we want to write. The great thing is that there’s certainly an API for that in the JAMstack! In this demo, we’ll explore integrating Auth0 with Fauna. We can use the integration in many ways.
Setting Up Auth0 To Connect With Fauna
Many implementations of authentication with the JAMstack rely heavily on Serverless functions. That moves much of the security concerns from a security-focused company like Auth0 to the individual developer. That doesn’t feel quite right.The typical flow would be to send a login request to a serverless function. That function would request a user from Auth0. Auth0 would provide the user’s JSON Web Token (JWT) and the function would provide any additional information about the user our application needs. The function would then bundle everything up and send it to the browser.
There are a lot of places in that authentication flow where a developer could introduce a security hole.
Instead, let’s request that Auth0 bundle everything up for us inside the JWT it sends. Keeping security in the hands of the folks who know it best.
We’ll do this by using Auth0’s Rules functionality to ask Fauna for a user token to encode into our JWT. This means that unlike our Guestbook, we won’t have any Fauna keys in our front-end code. Everything will be managed in memory from that JWT token.
Setting up Auth0 Application and Rule
First, we’ll need to set up the basics of our Auth0 Application.Following the configuration steps in their basic walkthrough gets the important basic information filled in. Be sure to fill out the proper localhost port for your bundler of choice as one of your authorized domains.
After the basics of the application are set up, we’ll go into the “Rules” section of our account.
Click “Create Rule” and select “Empty Rule” (or start from one of their many templates that are helpful starting points).
Here’s our Rule code
From there, we want to send a query to Fauna to create or log in our user. To keep our Rule code simple (and make it reusable), we’ll write our first Fauna “User-Defined Function” (UDF). A UDF is a function written in FQL that runs on Fauna’s infrastructure.
First, we’ll set up a Collection for our users. You don’t need to make a first Document here, as they’ll be created behind the scenes by our Auth0 rule whenever a new Auth0 user is created.
Next, we need an Index to search our
users
Collection based on the email address. This Index is simpler than our
Guestbook, so we can add it to the Dashboard. Name the Index user_by_email
, set the Collection to users
, and the Terms to data.email
. This will allow us to pass an email address to the Index and get a matching user Document back.It’s time to create our UDF. In the Dashboard, navigate to “Functions” and create a new one named
user_login_or_create
.users
Collection, it will create a Token for the user and send that back. If a
user doesn’t exist, it will create that user Document and then send a
Token to our Auth0 Rule.We can then store the Token as an
idToken
attached to the context
in our JWT. The token needs a URL as a key. Since this is a Fauna
token, we can use a Fauna URL. Whatever this is, you’ll use it to access
this in your code.This Token doesn’t have any permissions yet. We need to go into our Security rules and set up a new Role.
We’ll create an “AuthedUser” role. We don’t need to add any permissions yet, but as we create new UDFs and new Collections, we’ll update the permissions here. Instead of generating a new Key to use this Role, we want to add to this Role’s “Memberships”. On the Memberships screen, you can select a Collection to add as a member. The documents in this Collection (in our case, our Users), will have the permissions set on this role given via their Token.
Now, when a user logs in via Auth0, they’ll be returned a Token that matches their user Document and has its permissions.
From here, we come back to our application.
Implement logic for when the User is logged in
Auth0 has an excellent walkthrough for setting up a “vanilla” JavaScript single-page application. Most of this code is a refactor of that to fit the code splitting of this application.First, we’ll need the Auth0 SPA SDK.
Next, we set up a function that can be exported and used in multiple files to check if a user is logged in. The Auth0 library provides an
isAuthenticated()
method. If the user is authenticated, we can return the user data with auth0.getUser()
.We set up a
login()
and logout()
functions and a loadAuth()
function to handle the return from Auth0 and change the state of our UI to the “Mission” screen with today’s Mindful idea.Once this is all set up, we have our authentication and user login squared away.
We’ll create a new function for our Fauna functions to reference to get the proper token set up.
Generate a random Mindful topic and store it in Fauna
To start, we need a Collection of items to store our list of Mindful objects. We’ll create a Collection called “mindful” things, and create a number of items with the following schema:getUserClient()
method.From there, we’ll grab all the Documents from our
mindful_things
Collection. Paginate()
by default grabs 64 items per page, which is more than enough for our
data. We’ll grab a random item from the array that’s returned from
Fauna. This will be what Fauna refers to as a “Ref”. A Ref is a full
reference to a Document that the various FQL functions can use to locate
a Document.We’ll pass that Ref to a new UDF that will handle storing a new, timestamped object for that user stored in a new
user_things
Collection.We’ll create the new Collection, but we’ll have our UDF provide the data for it when called.
We’ll create a new UDF in the Fauna dashboard with the name
addUserMindful
that will accept that random Ref.As with our login UDF before, we’ll use the
Lambda()
FQL method which takes an array of arguments.Without passing any user information to the function, FQL is able to obtain our User Ref just calling the
Identity()
function. All we have from our randomRef
is the reference to our Document. We’ll run a Get()
to get the full object. We’ll the Create()
a new Document in the user_things
Collection with our User Ref and our random information.We then return the
creation
object back out of our Lambda. We then go back to our JavaScript and return the data object with the mindful
key back to where this function gets called.Render our Mindful Object on the page
When our user is authenticated, you may remember it called achangeToMission()
method. This function switches the items on the page from the “Home”
screen to markup that can be filled in by our data. After it’s added to
the page, the renderToday()
function gets called to add content by a few rules.The first rule of Serverless Data Club is not to make HTTP requests unless you have to. In other words, cache when you can. Whether that’s creating a full PWA-scale application with Service Workers or just caching your database response with localStorage, cache data, and fetch only when necessary.
The first rule of our conditional is to check localStorage. If localStorage does contain a
currentMindfulItem
, then we need to check its date to see if it’s from today. If it is, we’ll render that and make no new requests.The second rule of Serverless Data Club is to make as few requests as possible without the responses of those requests being too large. In that vein, our second conditional rule is to check the latest item from the current user and see if it is from today. If it is, we’ll store it in localStorage for later and then render the results.
Finally, if none of these are true, we’ll fire our
getRandomMindfulFromFauna()
function, format the result, store that in localStorage, and then render the result.Get the latest item from a user
I glossed over it in the last section, but we also need some functionality to retrieve the latest mindful object from Fauna for our specific user. In ourgetLatestFromFauna()
method, we’ll again instantiate our Fauna client and then call a new UDF.Our new UDF is going to call a Fauna Index. An Index is an efficient way of doing a lookup on a Fauna database. In our case, we want to return all
user_things
by the user
field. Then we can also sort the result by timestamp and reverse the default ordering of the data to show the latest first.Simple Indexes can be created in the Index dashboard. Since we want to do the reverse sort, we’ll need to enter some custom FQL into the Fauna Shell (you can do this in the database dashboard Shell section).
This creates an Index named
getMindfulByUserReverse
, created from our user_thing
Collection. The terms
object is a list of fields to search by. In our case, this is just the user
field on the data object. We then provide values
to return. In our case, we need the Ref and the Timestamp and we’ll use the reverse
property to reverse order our results by this field.We’ll create a new UDF to use this Index.
Lambda()
function doesn’t need any arguments since we’ll have our User based on the Token used.First, we’ll check to see if there’s at least 1 item in our Index. If there is, we’ll grab the first item’s data and time and return that back as a merged object.
After we get the latest from Fauna in our JavaScript, we’ll format it to a structure our
storeCurrent()
and render()
methods expect it and return that object.Now, we have an application that creates, stores, and fetches data for a daily message to contemplate. A user can use this on their phone, on their tablet, on the computer, and have it all synced. We could turn this into a PWA or even a native app with a system like Ionic.
We’re still missing one feature. Viewing a certain number of past items. Since we’ve stored this in our database, we can retrieve them in whatever way we need to.
Pull the latest X Mindful Missions to get a picture of what you’ve thought about
We’ll create a new JavaScript method paired with a new UDF to tackle this.getSomeFromFauna
will take an integer count
to ask Fauna for a certain number of items.Our UDF will be very similar to the
getLatestFromFauana
UDF. Instead of returning the first item, we’ll Take()
the number of items from our array that matches the integer that gets
passed into our UDF. We’ll also begin with the same conditional, in case
a user doesn’t have any items stored yet.Where To Go With Serverless Data
The JAMstack isn’t just for sites. It can be used for robust applications as well. Whether that’s for a game, CRUD application or just to be mindful of your surroundings you can do a lot without sacrificing customization and without spinning up your own non-dist database system.With performance on the mind of everyone creating on the JAMstack — whether for cost or for user experience — finding a good place to store and retrieve your data is a high priority. Find a spot that meets your needs, those of your users, and meets ideals of the JAMstack.
No comments:
Post a Comment