❥ Sponsor
The Jamstack is a modern web development architecture based on client-side JavaScript, reusable APIs, and prebuilt Markup.
The key aspects of a Jamstack application are the following:
In this article, we will learn how to build a Jamstack application that has:
We all love shopping. How cool would it be to manage all of our shopping notes in a centralized place? So we’ll be building an app called ‘shopnote’ that allows us to manage shop notes. We can also add one or more items to a note, mark them as done, mark them as urgent, etc.


At the end of this article, our shopnote app will look like this,
We will learn things with a step-by-step approach in this article. If you want to jump into the source code or demonstration sooner, here are links to them.
Fauna is the data API for client-serverless applications. If you are familiar with any traditional RDBMS, a major difference with Fauna would be, it is a relational NOSQL system that gives all the capabilities of the legacy RDBMS. It is very flexible without compromising scalability and performance.
Fauna supports multiple APIs for data-access,
In this article we will explain the usages of GraphQL for the ShopNote application.
First thing first, sign up using this URL. Please select the free plan which is with a generous daily usage quota and more than enough for our usage.
Next, create a database by providing a database name of your choice. I have used shopnotes as the database name.
After creating the database, we will be defining the GraphQL schema and importing it into the database. A GraphQL schema defines the structure of the data. It defines the data types and the relationship between them. With schema we can also specify what kind of queries are allowed.
At this stage, let us create our project folder. Create a project folder somewhere on your hard drive with the name, shopnote. Create a file with the name, shopnotes.gql with the following content:
Here we have defined the schema for a shopnote list and item, where each ShopNote contains name, description, update time and a list of Items. Each Item type has properties like, name, urgent, checked and which shopnote it belongs to.
Note the @relation directive here. You can annotate a field with the @relation directive to mark it for participating in a bi-directional relationship with the target type. In this case, ShopNote and Item are in a one-to-many relationship. It means, one ShopNote can have multiple Items, where each Item can be related to a maximum of one ShopNote.
You can read more about the @relation directive from here. More on the GraphQL relations can be found from here.
As a next step, upload the shopnotes.gql file from the Fauna dashboard using the IMPORT SCHEMA button,
Upon importing a GraphQL Schema, FaunaDB will automatically create, maintain, and update, the following resources:
Behind the scene, Fauna will also help to create the documents automatically. We will see that in a while.
Fauna supports a schema-free object relational data model. A database in Fauna may contain a group of collections. A collection may contain one or more documents. Each of the data records are inserted into the document. This forms a hierarchy which can be visualized as:
Here the data record can be arrays, objects, or of any other supported types. With the Fauna data model we can create indexes, enforce constraints. Fauna indexes can combine data from multiple collections and are capable of performing computations.


At this stage, Fauna already created a couple of collections for us, ShopNote and Item. As we start inserting records, we will see the Documents are also getting created. We will be able view and query the records and utilize the power of indexes. You may see the data model structure appearing in your Fauna dashboard like this in a while,
Point to note here, each of the documents is identified by the unique ref attribute. There is also a ts field which returns the timestamp of the recent modification to the document. The data record is part of the data field. This understanding is really important when you interact with collections, documents, records using FQL built-in functions. However, in this article we will interact with them using GraphQL queries with Netlify Functions.
With all these understanding, let us start using our Shopenotes database that is created successfully and ready for use.
Even though we have imported the schema and underlying things are in place, we do not have a document yet. Let us create one. To do that, copy the following GraphQL mutation query to the left panel of the GraphQL playground screen and execute.
Note, as Fauna already created the GraphQL mutation classes in the background, we can directly use it like, createShopNote. Once successfully executed, you can see the response of a ShopNote creation at the right side of the editor.
The newly created ShopNote document has all the required details we have passed while creating it. We have seen ShopNote has a one-to-many relation with Item. You can see the shopnote response has the item data nested within it. In this case, one shopnote has three items. This is really powerful. Once the schema and relation are defined, the document will be created automatically keeping that relation in mind.
Now, let us try fetching all the shopnotes. Here is the GraphQL query:
Let’s try the query in the playground as before:
Now we have a database with a schema and it is fully operational with creating and fetch functionality. Similarly, we can create queries for adding, updating, removing items to a shopnote and also updating and deleting a shopnote. These queries will be used at a later point in time when we create the serverless functions.
If you are interested to run other queries in the GraphQL editor, you can find them from here,
Next, we need to create a secured server key to make sure the access to the database is authenticated and authorized.
Click on the SECURITY option available in the FaunaDB interface to create the key, like so,
On successful creation of the key, you will be able to view the key’s secret. Make sure to copy and save it somewhere safe.
We do not want anyone else to know about this key. It is not even a good idea to commit it to the source code repository. To maintain this secrecy, create an empty file called .env at the root level of your project folder.
Edit the .env file and add the following line to it (paste the generated server key in the place of, <YOUR_FAUNA_KEY_SECRET>).
Add a .gitignore file and write the following content to it. This is to make sure we do not commit the .env file to the source code repo accidentally. We are also ignoring node_modules as a best practice.
We are done with all that had to do with Fauna’s setup. Let us move to the next phase to create serverless functions and APIs to access data from the Fauna data store. At this stage, the directory structure may look like this,
Netlify is a great platform to create hassle-free serverless functions. These functions can interact with databases, file-system, and in-memory objects.
Netlify functions are powered by AWS Lambda. Setting up AWS Lambdas on our own can be a fairly complex job. With Netlify, we will simply set a folder and drop our functions. Writing simple functions automatically becomes APIs.
First, create an account with Netlify. This is free and just like the FaunaDB free tier, Netlify is also very flexible.
Now we need to install a few dependencies using either npm or yarn. Make sure you have nodejs installed. Open a command prompt at the root of the project folder. Use the following command to initialize the project with node dependencies,
Install the netlify-cli utility so that we can run the serverless function locally.
Now we will install two important libraries, axios and dotenv. axios will be used for making the HTTP calls and dotenv will help to load the FAUNA_SERVER_SECRET environment variable from the .env file into process.env.
Or:
Create a folder with the name, functions at the root of the project folder. We are going to keep all serverless functions under it.
Now create a subfolder called utils under the functions folder. Create a file called query.js under the utils folder. We will need some common code to query the data store for all the serverless functions. The common code will be in the query.js file.
First we import the axios library functionality and load the .env file. Next, we export an async function that takes the query and variables. Inside the async function, we make calls using axios with the secret key. Finally, we return the response.
Create a file with the name, get-shopnotes.js under the functions folder. We will perform a query to fetch all the shop notes.
Time to test the serverless function like an API. We need to do a one time setup here. Open a command prompt at the root of the project folder and type:
This will open a browser tab and ask you to login and authorize access to your Netlify account. Please click on the Authorize button.
Next, create a file called, netlify.toml at the root of your project folder and add this content to it,
This is to tell Netlify about the location of the functions we have written so that it is known at the build time.
Netlify automatically provides the APIs for the functions. The URL to access the API is in this form, /.netlify/functions/get-shopnotes which may not be very user-friendly. We have written a redirect to make it like, /api/get-shopnotes.
Ok, we are done. Now in command prompt type,
By default the app will run on localhost:8888 to access the serverless function as an API.
Open a browser tab and try this URL, http://localhost:8888/api/get-shopnotes:
Congratulations!!! You have got your first serverless function up and running.
Let us now write the next serverless function to create a ShopNote. This is going to be simple. Create a file named, create-shopnote.js under the functions folder. We need to write a mutation by passing the required parameters.
Please give your attention to the parameter, ShopNotesItemRelation. As we had created a relation between the ShopNote and Item in our schema, we need to maintain that while writing the query as well.
We have de-structured the payload to get the required information from the payload. Once we got those, we just called the query method to create a ShopNote.
Alright, let’s test it out. You can use postman or any other tools of your choice to test it like an API. Here is the screenshot from postman.
Great, we can create a ShopNote with all the items we want to buy from a shopping mart. What if we want to add an item to an existing ShopNote? Let us create an API for it. With the knowledge we have so far, it is going to be really quick.
Remember, ShopNote and Item are related? So to create an item, we have to mandatorily tell which ShopNote it is going to be part of. Here is our next serverless function to add an item to an existing ShopNote.
We are passing the item properties like, name, if it is urgent, the check value and the note the items should be part of. Let’s see how this API can be called using postman,
As you see, we are passing the id of the note while creating an item for it.
We won’t bother writing the rest of the API capabilities in this article,  like updating, deleting a shop note, updating, deleting items, etc. In case, you are interested, you can look into those functions from the GitHub Repository.
However, after creating the rest of the API, you should have a directory structure like this,
We have successfully created a data store with Fauna, set it up for use, created an API backed by serverless functions, using Netlify Functions, and tested those functions/routes.
Congratulations, you did it. Next, let us build some user interfaces to show the shop notes and add items to it. To do that, we will use Gatsby.js (aka, Gatsby) which is a super cool, React-based static site generator.
The following section requires you to have basic knowledge of ReactJS. If you are new to it, you can learn it from here. If you are familiar with any other user interface technologies like, Angular, Vue, etc feel free to skip the next section and build your own using the APIs explained so far.
We can set up a Gatsby project either using the starter projects or initialize it manually. We will build things from scratch to understand it better.
Install gatsby-cli globally.


Install gatsby, react and react-dom
Edit the scripts section of the package.json file to add a script for develop.
Gatsby projects need a special configuration file called, gatsby-config.js. Please create a file named, gatsby-config.js at the root of the project folder with the following content,
Let’s create our first page with Gatsby. Create a folder named, src at the root of the project folder. Create a subfolder named pages under src. Create a file named, index.js under src/pages with the following content:
Let’s run it. We generally need to use the command gatsby develop to run the app locally. As we have to run the client side application with netlify functions, we will continue to use, netlify dev command.
That’s all. Try accessing the page at http://localhost:8888. You should see something like this,
Gatsby project build creates a couple of output folders which you may not want to push to the source code repository. Let us add a few entries to the .gitignore file so that we do not get unwanted noise.
Add .cache, node_modules and public to the .gitignore file. Here is the full content of the file:
At this stage, your project directory structure should match with the following:
We will create small logical components to achieve the ShopNote user interface. The components are:
You can see the sections marked in the picture below:
We will install a few more dependencies required for the user interfaces to be functional and look better. Open a command prompt at the root of the project folder and install these dependencies,
We will use the Reactjs useEffect hook to make the API call and update the shopnotes state variables. Here is the code to fetch all the shop notes.
Finally, let us change the return section to use the shopnotes data. Here we are checking if the data is loaded. If so, render the Shopnotes component by passing the data we have received using the API.
You can find the entire index.js file code from here The index.js file creates the initial route(/) for the user interface. It uses other components like, Shopnotes, Note and Item to make the UI fully operational. We will not go to a great length to understand each of these UI components. You can create a folder called components under the src folder and copy the component files from here.
Now we just need a css file to make things look better. Create a file called index.css under the pages folder. Copy the content from this CSS file to the index.css file.
That’s all. We are done. You should have the app up and running with all the shop notes created so far. We are not getting into the explanation of each of the actions on items and notes here not to make the article very lengthy. You can find all the code in the GitHub repo. At this stage, the directory structure may look like this,
I have not included the Create Note UI implementation in the GitHib repo. However, we have created the API already. How about you build the front end to add a shopnote? I suggest implementing a button in the header, which when clicked, creates a shopnote using the API we’ve already defined. Give it a try!
All good so far. But there is one issue. We are running the app locally. While productive, it’s not ideal for the public to access. Let’s fix that with a few simple steps.
Make sure to commit all the code changes to the Git repository, say, shopnote. You have an account with Netlify already. Please login and click on the button, New site from Git.
Next, select the relevant Git services where your project source code is pushed. In my case, it is GitHub.
Browse the project and select it.
Provide the configuration details like the build command, publish directory as shown in the image below. Then click on the button to provide advanced configuration information. In this case, we will pass the FAUNA_SERVER_SECRET key value pair from the .env file. Please copy paste in the respective fields. Click on deploy.
You should see the build successful in a couple of minutes and the site will be live right after that.
To summarize:
Thank you for reading this far! Let’s connect. You can @ me on Twitter (@tapasadhikary) with comments, or feel free to follow.
Frontend Masters is the best place to get it. They have courses on all the most important front-end technologies, from React to CSS, from Vue to D3, and beyond with Node.js and Full Stack.

ShopTalk is a podcast all about front-end web design and development.

source