What distinguishes plain static sites from Jamstack sites?
Their use of data from APIs.
While a traditional static site might use file-based data like Markdown and YAML, a Jamstack site frequently uses things like a headless CMS or e-commerce.
Headless CMS and API-driven services like Algolia fill many needs but are built for particular purposes. Your Jamstack site might need to store and access data that doesn't fit into the CMS archetype, for instance. In those cases, you might need a... database!
Fauna is one solid option. It is a cloud-based transactional serverless database that makes that data available via a data API. This makes it ideal for use in a Jamstack application.
A great piece about FaunaDB with its CEO here.
This article will explore how to get started using FaunaDB and Next.js to connect a database to a Jamstack site built in the React framework.
We'll cover:
More about serverless architectures here.
Setting up FaunaDB
Fauna databases provide many ways to get started. You can use the web-based admin to create and manage new databases. However, you can also do most actions via the Fauna Shell, a CLI for interacting with Fauna, which is what we'll use for this tutorial.
npm install -g fauna-shell
Now we can log in.
fauna cloud-login
You'll need to enter your email and password. If you signed up using third-party authentication like Netlify or GitHub, you need to create the database via the web admin and get a security key in the security tab of the database.
Fauna documentation about cloud-login here
We'll create a simple application using Next.js that will be a list of shows that I want to watch. Let's create a new database to store this data.
fauna create-database my_shows
At this point, we can use the shell to interact with the database and create new collections, which are Fauna's equivalent of a table.
fauna shell my_shows
You should see something like the following:
Starting shell for database my_shows
Connected to https://db.fauna.com
Type Ctrl + D or .exit to exit the shell
my_shows>
Using FQL (Fauna Query Language) to create and query data
Once inside the shell, you can interact with your new database using FQL (Fauna Query Language). FQL is essentially Fauna's API language for creating, updating, and querying data. However, it isn't an API in the way you're probably used to using one. It includes things like data types, built in functions and even user defined functions that make it feel more like a programming language than a typical API. There's a lot you can do with FQL, more than we can cover in-depth here. Be sure to refer to the documentation for a full overview.
Let's start by creating a collection called "shows."
CreateCollection({ name: "shows" })
A
collection in Fauna stores documents. If you are more comfortable with a
traditional relational database model, you can think of these as table
rows. We could create a single document using the Create()
method, but instead, populate multiple documents using the Map()
method. We'll map over a nested array of values. Each of the nested
arrays represents the values of one document. We'll use these to
populate the two properties in our document, title
and watched
. For now, we'll set watched
on all these dummy items to false
to indicate we have not yet watched them.
Map(
[
["Kim's Convenience",false],
["I'm Sorry",false],
["The Good Place",false]
],
Lambda(["title","watched"],
Create(
Collection("shows"), { data: { title: Var("title"), watched: Var("watched")} }
)
)
)
Lastly, let's query for all the documents in our "shows" collection. In this case, we'll use Collection()
to define which collection we are pulling from, Documents()
to say that we want all the references to each document in our shows collection, and then Paginate()
to convert these references to Page objects. Each page will be passed to the Lambda()
function, where they will be used to Get()
the full record.
Map(
Paginate(Documents(Collection("shows"))),
Lambda(show => Get(show))
)
You should see a result like:
{
data: [
{
ref: Ref(Collection("shows"), "293065998672593408"),
ts: 1615748366168000,
data: { title: "I'm Sorry", watched: false }
},
{
ref: Ref(Collection("shows"), "293065998672594432"),
ts: 1615748366168000,
data: { title: 'The Good Place', watched: false }
},
{
ref: Ref(Collection("shows"), "293065998672595456"),
ts: 1615748366168000,
data: { title: "Kim's Convenience", watched: false }
}
]
}
Finally, before we move on, we should create an index for this collection. Among other things, the index will make it easier to locate a document, updating the records easier.
CreateIndex({
name: "shows_by_title",
source: Collection("shows"),
terms: [{ field: ["data", "title"] }]
})
Now that we have our database created and populated let's move to use it within a Next.js app.
Getting data in Next.js with FaunaDB
We're going to walk through creating a simple web app using Next.js that uses our Fauna table to allow us to add shows we want to watch and mark the shows we've watched as done. This will demonstrate how to read data from Fauna and display it in Next.js, create new records in Fauna, and update an existing record.
The code for this sample is available in GitHub. It borrows the layout from this CodePen. You can see what the app looks like below.
To use the sample yourself, you'll need to provide a .env
file with a value for FAUNADB_SECRET
that contains a key from Fauna to connect to your shows
collection. To obtain a key, go to the "Security" tab within your collection on the Fauna dashboard and create a new key.
We won't cover every detail of building a Next.js app here as it is just a single page. We'll explore some of the basic pieces that you need to understand to use Fauna.
You can follow this tutorial from Vercel to get started with Next.js
Fauna JavaScript driver
To query Fauna within our app, we're going to use the Fauna JavaScript driver. This is a Node.js library for integrating with Fauna. It allows you to run the same FQL queries that we ran within the Fauna Shell from your Node application. To add this to a new Next.js application, you need to run:
npm install faunadb
Within Node, you need to instantiate the client with your Fauna key. We can do this from within a /lib/fauna.js
file that we will include wherever we need to access data in Fauna. It gets the key from an environment variable called FAUNADB_SECRET
that is within a .env.local
file.
import faunadb from 'faunadb';
export const faunaClient = new faunadb.Client({
secret: process.env.FAUNADB_SECRET,
});
Protecting your API key
Before we begin getting data, there's one area of concern. Since our application data is all user-generated, it is getting all of its Fauna data client-side rather than at build time. This means that anyone inspecting the API call would have access to the Fauna key.
There are two ways to handle this:
1. Create a key that has very restricted permissions set within the Fauna dashboard to limit misuse.
This still exposes the key but limits the potential for misuse. It's handy if you are reading data and limit the key to read-only.
2. Create a serverless function that is an intermediary for calling the Fauna API, thereby hiding your key entirely.
This is the more secure option because it never exposes the key at all. Users can still call the endpoint if they inspect how, but the API limits what they can do.
Luckily, within Next.js, there is an easy way to accomplish the second option by using Nextjs API routes.
All of the interaction with Fauna within this sample app will go through one of three API routes: getShows
; addShows
; or updateShows
.
Getting data from Fauna database
From a Fauna Query Language standpoint, reading data from Fauna is pretty straightforward. We'll use the same Map()
function we used within the Fauna Shell earlier. We need to do it in the context of the client that we instantiated earlier.
from https://snipcart.com/blog/nextjs-faunadb
No comments:
Post a Comment