Working with Cloudinary, Xata, and Next.js - Building an eatery menu
Tags: nextjs, cloudinary, xata, beginners
Published: 2022-11-23 22:59:40

Every organization relies on databases, which store vast amounts of highly sensitive and private data. Be it a restaurant, bank or hospital; each must ensure enough technical safeguards to protect these databases and stop unauthorized individuals from accessing contents, as a database's information is a valuable asset. 

This article demonstrates creating an eatery menu using Cloudinary to manage media-related assets and integrate Xata’s out-of-box functionalities to store and dish out sensitive data.

The complete source code of this project is on [GitHub](https://github.com/ugwutotheeshoes/pizzarini). Fork it to get started quickly. A live demo of the application is also available on [Netlify](https://pizzarini.netlify.app/).


## Prerequisite

To comfortably follow along in this article, it would be helpful to have the following:

- Adequate knowledge of [React ](https://reactjs.org?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)and [Next.js](https://nextjs.org?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog).
- [Node](https://nodejs.org/) and its package manager, `npm`. Run the command `node -v && npm -v` to verify that you have them installed, or install them from [here](https://nodejs.org/en/).
- A [Xata](https://xata.io?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) account - Create one [here](https://app.xata.io/signin).
- A [Cloudinary](https://cloudinary.com?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) account - Create one [here](https://cloudinary.com/homepage-2).


> NOTE: Do not share your Xata or Cloudinary API Key and API Secret with anyone.


## Getting Started
### Project setup and installation

To create a new project, we’ll run the following command in our terminal:

```js
npx create-next-app <project-name>
```

Navigate into the project directory and install the necessary dependencies, `@xata.io/client` to integrate Xata, `dotenv` to access sensitive credentials, and `react-icons` for icons.

```js
cd <project-name> && npm install @xata.io/client dotenv react-icons -g
```

Running `npm run dev` will start the development server by default at `http://localhost:3000` in our browser.


> NOTE: `<project-name>` above stands for the name of your app. Call it whatever name you want.


### Setting up our Cloudinary images

After successfully creating an account, Cloudinary redirects us to our account's dashboard. Click on the Upload button to add the images needed for the eatery menu.

![Cloudinary dashboard](https://paper-attachments.dropboxusercontent.com/s_26AAEF0D90C90F3F11A303A9E1648643DD7F9B8E91C46DB50B168D60A3FD8DFA_1647703970475_Cloudinary-Management-Console-Media-Library+1.png)


After adding the images, copy the image URLs; we'll use them later.


### Setting up a Xata project

[Xata](https://xata.io/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) is a serverless data platform that provides an abstraction layer on top of several data stores to simplify the development and administration of applications. Behind the scenes, Xata uses the PostgreSQL database, regarded as one of the best tools based on Postgres. Xata’s RESTful API also offers advanced search and analytics from a search engine/column store, Elasticsearch.

To get started, create an account in Xata [here](https://app.xata.io/signin). After logging in, we’ll be redirected to Xata’s workspace dashboard, as shown below, where we’ll create a new Xata database for the demo application. Click the Add a database button and add a suitable name for the database.

![Create a database](https://paper-attachments.dropboxusercontent.com/s_E97AD316A7ED1144B1A4F9E59DC538736066628CBF4856FF4B8F78F84DAC96E5_1668380296752_Emmanuel-Ugwu-s-workspace.png)
![Add a database name](https://paper-attachments.dropboxusercontent.com/s_E97AD316A7ED1144B1A4F9E59DC538736066628CBF4856FF4B8F78F84DAC96E5_1668380504467_Emmanuel-Ugwu-s-workspace+2.png)


Once the database is created, we’ll create our application’s sample data. Xata provides different varieties when creating sample data, but we’ll choose the Start from scratch option.

![Creating sample data](https://paper-attachments.dropboxusercontent.com/s_E97AD316A7ED1144B1A4F9E59DC538736066628CBF4856FF4B8F78F84DAC96E5_1668380578886_pizzarini-main--Emmanuel-Ugwu-s-workspace.png)


Click the + icon to define the schema of the table. All the tables have a required column - the `id` column, which provides a unique identity for each row.

![Creating data samples](https://paper-attachments.dropboxusercontent.com/s_E97AD316A7ED1144B1A4F9E59DC538736066628CBF4856FF4B8F78F84DAC96E5_1668381121692_Table-pizza-menu--pizzarini-main--Emmanuel-Ugwu-s-workspace+1.png)

Let’s now create a data sample for our application. The data sample consists of our menu’s name, price, description, and image hosted on Cloudinary. Later we’ll fetch the data sample using Xata's REST API.

![Creating extra columns](https://paper-attachments.dropboxusercontent.com/s_E97AD316A7ED1144B1A4F9E59DC538736066628CBF4856FF4B8F78F84DAC96E5_1668381499274_Table-pizza-menu--pizzarini-main--Ugwu-s-workspace+1.png)

### Adding Xata to our application

To authenticate Xata into our application, let’s run the following command in the terminal: 

```js
xata auth login
```

This command will prompt a message to either Create a new API key or Use an existing API key.
In this tutorial, we will use an existing key. However, to create a new API key, click the profile icon on Xata’s dashboard and select Account Settings.

![Generating an API key](https://paper-attachments.dropboxusercontent.com/s_E5AAF1B0BD9D57469E420D9AF79A58222EFAC0ACBD8BE58749485C94E8DB4FDD_1667905707395_image.png)

After creating the API key, Xata CLI will authenticate our application. We will also initialize a Xata project in our application.

```js
xata init
```

Xata will present us varieties of options from which we can choose. This generates files to help with the data-fetching process. After the code and file generation process, we’ll add our credentials - API Key and Database URL in the generated `.env` file at the root directory of our project to hide them as they are sensitive information.

```js
XATA_API_KEY="OUR_API_KEY"
XATA_DATABASE_URL="OUR_DATABASE_URL"
```

### Building the app component

While still in development, replace the default syntax in the `index.js` file with the code snippet below.

```js
export default function Home(){
  return (
<div className={styles.App}>
    <div className={styles.icon}>
       <div className={styles.logo}>
           <h2>Luigi's Pizza</h2>
           <FaPizzaSlice className={styles.slice} />
       </div>
     </div>
<div className={styles.toggle}>
      <p className={styles.itemText}>Step into heaven in the form of a pizza slice.</p>
      <button>see pizza menu</button>
</div>
      <footer className={styles.footer}>Luigi's Pizza | 2022</footer>
</div>
  );
};
```

With the default syntax replaced, our app will look something like this:

![Current Homepage](https://paper-attachments.dropboxusercontent.com/s_E97AD316A7ED1144B1A4F9E59DC538736066628CBF4856FF4B8F78F84DAC96E5_1668426729672_React-App+6.png)

### Fetching menus from Xata

In this tutorial section, we want to fetch our eatery’s menu from Xata’s database, hide the current page, and display the eatery menu whenever we click the see pizza menu button. To fetch data from Xata, we’ll use the `getServerSideProps` function in the `index.js`  file, which imports external data into the index page.

```js
import { BaseClient } from "@xata.io/client";
export async function getServerSideProps() {
const xata = new BaseClient({
    branch: "main",
    apiKey: process.env.XATA_API_KEY,
    databaseURL: process.env.XATA_DATABASE_URL
  });
const records = await xata.db["pizza-menu"].getAll();
   return {
    props: {
      pizzas: records,
     },
  };
}
```

Let’s loop through the data from Xata’s database to render each menu with its name, image, price and description.4

```js
export default function Home({ pizzas }) {
 return (
   <div className={styles.App}>
      <div className={styles.icon}> //Navbar </div>
        <div>// Homepage </div>
           <div className={styles.container}>
              {pizzas.map((menuItem) => {
                const { id, title, img, price, desc } = menuItem;
                return (
                  <article key={id} className={styles.menuItem}>
                    <img src={img} alt={title} className={styles.photo} />
                    <div className={styles.itemInfo}>
                      <header>
                        <h4>{title}</h4>
                        <h4 className={styles.price}>${price}</h4>
                      </header>
                      <p className={styles.itemText}>{desc}</p>
                    </div>
                  </article>
                );
              })}
        </div>
    </div>
  );
}
```

With the help of conditional rendering, we can create the hide/show effect we need for our application. Add the code snippet below to the `index.js` file.

```js
export default function Home() {  
const [isOpen, setIsOpen] = useState(false);
const toggle = (e) => {
   e.preventDefault();
   setIsOpen(true);
 };
const trigger = (e) => {
   e.preventDefault();
   setIsOpen(false);
 };
 return (
<div className={styles.App}>
   <div className={styles.icon}>
       <div className={styles.logo}>
           <h2>Luigi's Pizza</h2>
           <FaPizzaSlice className={styles.slice} />
        </div>
    {isOpen ? <button onClick={trigger}>go back</button> : ""}
   </div>
    {!isOpen ? (
   <div
     className={styles.toggle}
     style={isOpen ? { marginTop: 0 } : { marginTop: 280 }}
    >
     // eatery menu button
    </div>
        ) : ( "" )}
    {isOpen ? (
    <div className={styles.container}>
     // eatery menu
     </div>
        ) : ( "" )}
   </div>
      // footer
   );
}
```

After applying the necessary configurations, our app will look something like this:


![Our functional application](https://paper-attachments.dropboxusercontent.com/s_E97AD316A7ED1144B1A4F9E59DC538736066628CBF4856FF4B8F78F84DAC96E5_1668812745636_ezgif.com-gif-maker+16.gif)

## Conclusion

This article discussed using Xata's database and, more importantly, integrating Xata into web applications built with Next.js.

## Resources
- [Xata Documentation - Getting started with Xata CLI](https://xata.io/docs/intro/getting-started?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)
- [Cloudinary React SDK Documentation](https://cloudinary.com/documentation/react_quick_start?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)
- [Getting Started with Next.js](https://nextjs.org/docs/getting-started?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)