Learn How to Connect your Nextjs App to Sanity.io (Typescript)
Tags: webdev, tutorial, react, sanity
Published: 2022-11-05 06:55:22

`Hello my gorgeous friend from the Internet, today in this tutorial we will learn how to connect a minimalistic e-commerce web app to a CMS (Content Management System) that going to be used as a dashboard whenever you want to add a new item to your store.`

Whenever you need to update your content in a non-developer mode, or maybe you are building an application for a non-developer and you don't want to hardcode and re-deployed every single time you make changes.

## What You will learn

- Sanity.io (CMS)
- Groq query
- Connect your Nextjs frontend to Sanity.io

## Prerequisite

- Clone the repo and have it running on your local machine
- Solid understanding of Nextjs
-TailwindCss

## What is Sanity?

Sanity.io is a managed content management system (CMS) for creating websites. It features a modern interface, easy installation, and a built-in developer mode with live reloading.

Sanity is a versatile content management platform. It markets itself as flexible and can be used for much more than conventional web experiences. You can use Sanity with the NextJS framework to power simple marketing websites through an entire suite of web applications.

## Installation

We assume that your application is running on your local machine, mine looks something like this:
![e-commerce web app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zieour3fax6pqds2usqj.png)

Next we need to connect our Sanity CMS to our application.
before doing that let's install some dependencies:
In your terminal run this command: 
`npm i -g @sanity/cli`

Next run : 
`sanity init`

then you will have to follow the steps bellow to login to your sanity account.

![create sanity project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q9vfzpnvirmae3hup2k7.png)
Go ahead and follow the instructions to create your project.
![project setup](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ca4scbmpya182687l644.png)
after the installation is completed, navigate into your directory and run `sanity start` the server will start on port:3333

## Sanity.io

If you already working with firebase or any databases you might have an idea of what is going on here. We Have a list of documents.
Let's add a document to our application.

Inside our Sanity directory, we have a schemas folder where the shape of our application is implemented.

Go ahead and create a file name 'clients.js'

```javascript
export default {
  name: "clients",
  title: "Clients",
  type: "document",
  fields: [
    {
      name: "name",
      title: "Name",
      type: "string",
    },
    {
      name: "bio",
      title: "Bio",
      type: "text",
    },
  ],
};

```

## Explanation 
We created a document gave it a name, title, and type, and then we specified the fields that the document will have.

Let's proceed, in Schema.js import the document we just created `import clients from ./clients.js` 
To allow sanity to be aware of our Schema let's put it in the builder like this:
```javascript
...
import clients from "./clients";

export default createSchema({
  name: "default",
  types: schemaTypes.concat([
    // The following are document types which will appear
    // in the studio.
    ...
    clients,
  ]),
});

```
Now save all files and the result should be reflected in our sanity studio.
![sanity studio](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v1sj653yijjegeqdzewt.png)

## How to reference another document

Let's say we want to reference a product to its vendor
this code snippet shows how to do that:
```javascript
{
      name: "products",
      title: "Products",
      type: "array",
      of: [
        {
          type: "reference",
          to: { type: "vendor" },
        },
      ],
    },
```
Now my friend you know how to create a document in Sanity.
let's go ahead and create products, vendors, and categories by following the same structure we did earlier.

**products document**:

```javascript
export default {
  name: "product",
  title: "Product",
  type: "document",
  fields: [
    {
      name: "title",
      title: "Title",
      type: "string",
    },
    {
      name: "slug",
      title: "Slug",
      type: "slug",
      options: {
        source: "title",
        maxLength: 96,
      },
    },
    {
      title: "Size",
      name: "size",
      type: "array",
      of: [
        {
          type: "string",
        },
      ],
      options: {
        layout: "tags",
      },
    },
    {
      name: "categories",
      title: "Categories",
      type: "array",
      of: [
        {
          type: "reference",
          to: { type: "category" },
        },
      ],
    },
    {
      name: "description",
      title: "Description",
      type: "text",
      options: {
        maxLength: 120,
      },
    },
{
      title: "Price",
      name: "price",
      type: "number",
    },
    {
      name: "vendor",
      title: "Vendor",
      type: "reference",
      to: {
        type: "vendor",
      },
    },
  ],
  preview: {
    select: {
      title: "title",
      manufactor: "manufactor.title",
      media: "defaultProductVariant.images[0]",
    },
  },
};

```
**vendors document**:
```javascript

export default {
  name: "vendor",
  title: "Vendor",
  type: "document",
  fields: [
    {
      name: "title",
      title: "Title",
      type: "string",
    },
    {
      name: "slug",
      title: "Slug",
      type: "slug",
      options: {
        source: "title",
        maxLength: 96,
      },
    },
    {
      name: "logo",
      title: "logo",
      type: "image",
    },
    {
      name: "description",
      title: "Description",
      type: "text",
    },
  ],
  preview: {
    select: {
      title: "title",
      media: "logo",
    },
  },
};

```
**categories document**:
```javascript
export default {
  name: "category",
  title: "Category",
  type: "document",
  fields: [
    {
      name: "title",
      title: "Title",
      type: "string",
    },
    {
      name: "slug",
      title: "Slug",
      type: "slug",
      options: {
        source: "title",
        maxLength: 96,
      },
    },
    {
      name: "description",
      title: "Description",
      type: "text",
    },
  ],
};
```
Go ahead and save all files, Go to your sanity studio and add content to each collection.

## Deploying to sanity.io

to deploy your sanity project to sanity.io so it can be available remotely you need to deploy it by running the command `sanity deploy` click the link provide after the deployment is complete.

Now if you try to add an item to your store locally, the changes will be reflected on Sanity.io and vis-versa.

## Groq query

GROQ is Sanity's open-source query language. It's a powerful and intuitive language that's easy to learn. With GROQ you can describe exactly what information your application needs, join information from several sets of documents, and stitch together a very specific response with only the exact fields you need.

## Run some groq query

```javascript
//Querying everthing with _type products
*[_type == "products"]{
  ...,
}
```
Use this [cheat sheet](https://www.sanity.io/docs/query-cheat-sheet) to learn more about Groq query.

## Pull data from Sanity backend to our frondend

Let's start by installing some dependencies: 
run this commande in the terminal:
`npm i next-sanity @portabletext/react @sanity/image-url`

next add a Sanity.ts to the root of your app, inside we will create the config for the frontend to use.

inside Sanity.ts write the code below:
```javascript
import { createClient } from "next-sanity";
import createImageUrlBuilder from "@sanity/image-url";

export const config = {
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || "production",
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
  apiVersion: "2022-03-25",
  useCdn: true,
};
export const sanityClient = createClient(config);

export const urlFor = (source: any) =>
  createImageUrlBuilder(config).image(source);

```
next, create an .env.local file to store our credentials
⚠️do not forget to add this file in .gitignore so you won't accidentally push the file to GitHub.

```javascript
NEXT_PUBLIC_SANITY_DATASET=production
NEXT_PUBLIC_SANITY_PROJECT_ID=[your project_id]
```
to get this information log in to [https://sanity.io](sanity.io) with your account, and select your project in the top corner you will see the information you need for instance "the project id"
![sanity project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ae7j3kuisj2cv480qeda.png)

Next add util folder to the root of your app inside create a file called fetchProductData.ts and past this code in:
```javascript
import { groq } from "next-sanity";
import { sanityClient } from "sanity";
export const fetchProducts = async () => {
  const query = groq`
*[_type=="product"]{
    ...,
    vendors->{...,title,logo,description},
    categories[]->{slug,title},
  }
`;
  const res = await sanityClient.fetch(query);
  return res;
};
```
Let's console.log the function in one of your components and see if we are getting the data from our backend but before doing that we are going to do something called static page rendering into our Nextjs application when we update our page it will revalidate the page so the page will have fresh data every 10 seconds, it will rebuild the static page and prepare it on the server.

The way to get this working we go to our page in index.ts
write this code at the bottom of your code:
```javascript
import type { GetStaticProps } from "next";
import { Product } from "typings";
interface SanityBody {
  _createAt: string;
  _id: string;
  _rev: string;
  _updateAt: string;
}

interface Product extends SanityBody {
  _type: "product";
  title: string;
  categories: "Category[]";
  color: "string[]";
  defaultProductVariant: DefaultProductVariant;
  description: string;
  size: string[];
  slug: SlugT;
  tags: string[];
  title: string;
  vendor: Vendor;
}
...
const Home = ({ products }: Props) => {
//Console log to see if we got the data
console.log("data",products)
return(
...
)
}
export default Home;
export const getStaticProps: GetStaticProps<Props> = async () => {
  const products: Product[] = await fetchProducts();
  return {
    props: {
      products,
    },
    revalidate: 20,
  };
};

```
if we successfully get the data, now the last step left is to replace all our dummy data with fresh new data coming from Sanity.io I let you do that. Let me know in the comment section if you were able to pass the values got from the response.

All you need to do now is to deploy your application to Vercel. if you already deployed it all you need to do is push the changes to GitHub and Vercel will re-deploy your application automatically.

- See the demo of my e-commerce application [here](https://beyondart-online-shop.vercel.app/).
- Learn how to deploy your application to vercel [here](https://vercel.com/guides/deploying-react-with-vercel)

## Conclusion
Well my friend you've reached the end of the article,
I will advise you to go and put all that you've learned so far into practice and if you find something missing go and search more about it until your individual best pattern is formed. 

👋 see you for the next one.