Creating a Restaurant Finder Application Using ReactJS and Amplication
Tags: tutorial, javascript, api, webdev
Published: 2024-01-15 06:16:31


## Introduction


This tutorial will guide you through building a restaurant finder application. This full-stack web application will allow users to search for restaurants based on location (zip code) and view a list of restaurants that match their criteria. We'll create the backend and frontend components and demonstrate how to connect them to create a fully functional restaurant finder.

<div>
<img src="https://static-assets.amplication.com/blog/creating-a-restaurant-finder-full-stack-web-application-using-reactjs-and-amplication/0.png" alt="" style="margin-left: auto; margin-right: auto;" height="943" width="1910">
</div>
<br />

This tutorial will include how to create a backend using Amplication, create a frontend using ReactJS, and connect the backend created by Amplication to the frontend.


### Creating the backend:

In this part of the tutorial, we will use Amplication to develop the backend of our restaurant finder application. Amplication creates a fully functional production-ready backend with REST and GraphQL API, authentication, databases, best practices, etc., in a few minutes.



- Go to https://amplication.com.
- Login into it or make an account if you have not already.
- Create a new app and name it `restaurant-finder-backend.`
- Click on `Add Resource` and then on  `Service` and name it `restaurant-finder.`
- Then, connect your GitHub account to the one on which you want Amplication to push the backend code and select or create a repository.
- Choose which API you want; we will go by the default, and that is both.
- Choose `monorepo` in this step.
- Choose the database. We will go with `PostgreSQL`.
- We will create entities from scratch.
- We want to have `auth` in the app.
- Click on `create service,` and the code is generated now.
- Go to Entities and click on `add entity`:
  - Entity Name: `Restaurant`
  - First field: name [Searchable, Required, Single Line Text]
  - Second field: address [Searchable, Required, Single Line Text]
  - Third field: phone [Searchable, Required, Single Line Text]
  - Fourth field: zipCode [Searchable, Required, Single Line Text]

Click on `Commit Changes and Build,` and in a few minutes, the code will be pushed to the GitHub repository. Go to the repo and approve the Pull Request that Amplication created.

Now, you have all the backend code generated by Amplication in your GitHub repository.
It will look like this:


<div>
<img src="https://static-assets.amplication.com/blog/creating-a-restaurant-finder-full-stack-web-application-using-reactjs-and-amplication/1.png" alt="" style="margin-left: auto; margin-right: auto;" height="943" width="1910">
</div>
<br />

Backend Code: [https://github.com/souravjain540/restaurant-finder](https://github.com/souravjain540/restaurant-finder)

Now clone your repository, open it in the IDE of your choice, go to `restaurant-finder-backend/apps/restaurant-finder,` and follow these commands:

```
npm install
npm run prisma:generate
npm run docker:dev
npm run db:init
npm run start
```
After all these steps, you will have a backend running on `localhost:3000.` As Amplication comes with AdminUI and Swagger Documentation, you can go to `localhost:3000/api` and view all the endpoints of the API that amplication generated.


<div>
<img src="https://static-assets.amplication.com/blog/creating-a-restaurant-finder-full-stack-web-application-using-reactjs-and-amplication/2.png" alt="" style="margin-left: auto; margin-right: auto;" height="943" width="1910">
</div>
<br />

Let’s click on the auth and make a `POST` request by clicking on try it out with credentials `admin` and `admin.`


<div>
<img src="https://static-assets.amplication.com/blog/creating-a-restaurant-finder-full-stack-web-application-using-reactjs-and-amplication/3.png" alt="" style="margin-left: auto; margin-right: auto;" height="943" width="1910">
</div>
<br />

Now click on execute, copy the `accessToken,` and save it for the auth purpose later.

Now, we have our backend ready and running on our local system. It is now time to move to the frontend part.

_NOTE_: If you have any problems using Amplication while creating your web application or in the installation, please feel free to contact the Amplication Team on our Discord channel.


### Creating the frontend:

In this part, we will build the frontend of our restaurant finder application using React, a popular JavaScript library for building user interfaces. We'll create the user interface for searching restaurants by zipcode, displaying search results, and adding new restaurants.

#### Setting up React Project:

First, ensure your system has Node.js and npm (Node Package Manager) installed. If not, you can download and install them from the official Node.js website. 

Let's create a new React project using Create React App, a popular tool for setting up React applications with a predefined project structure. Open your terminal and run the following command:

```
npx create-react-app restaurant-finder
```

This command will create a new directory called `restaurant-finder` containing all the necessary files and folders for your React project. 

#### Designing the User Interface with Components 

In React, you build user interfaces by creating components. Let's design the components for our restaurant finder application. 

There will be three main components in our project:

1. SearchForm Component: This will be the main page of our project where the user will enter the `zipCode,` and all the restaurants with that `zipCode` will be shown as a list in the result. It will work in the root directory. (`/`)

2. RestaurantForm Component:  This page will be responsible for adding any new restaurant to the list of restaurants. It will be a form with all the relevant details. It will work at `/restaurants/add.`

3. RestaurantList Component: This page will show all the restaurants available in our database. It will work at `/restaurants.`

#### Directory Structure:

To avoid any confusion, the file structure will look like this:

<div>
<img src="https://static-assets.amplication.com/blog/creating-a-restaurant-finder-full-stack-web-application-using-reactjs-and-amplication/4.png" alt="" style="margin-left: auto; margin-right: auto;" height="943" width="1910">
</div>
<br />

### Create a SearchForm Component 

Inside the src folder of your project, create a new file named SearchForm.js. This component will be responsible for the restaurant search form. Let's break down the code snippet of `SearchForm.js` step by step:

1. Import Statements:
   ```
   import React, { useState } from 'react';
   import axios from 'axios';
   ```
   - The code begins with importing the necessary modules. 
   - `React` is imported to define React components.
   - `useState` is a React hook used to manage component-level state.
   - `axios` is imported to make HTTP requests to the backend API.

2. `getAuthToken` Function:

   ```
   const getAuthToken = () => {
     // Replace this with your logic to obtain the token
     return 'ebGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....'; // A placeholder token
   };
   ```
   - `getAuthToken` is a function that should be replaced with your actual logic to obtain an authentication token. 
   - In this code, it returns a placeholder token.

3. Axios Configuration:
   ```
   const api = axios.create({
     baseURL: 'http://localhost:3000/api', // Adjust the base URL to your API endpoint
     headers: {
       'Content-Type': 'application/json',
       Authorization: `Bearer ${getAuthToken()}`, // Attach the token here
     },
   });
   ```
   - `api` is an instance of Axios configured with a base URL for the backend API.
   - It sets the `Content-Type` header to indicate that the request body is in JSON format.
   - It also attaches an authorization header with the token obtained from `getAuthToken`.

4. `SearchForm` Component:
   ```
   function SearchForm({ onSearch }) {
     // ...
   }
   ```
   - `SearchForm` is a React functional component that takes a prop named `onSearch`.
   - Inside this component, we will create the UI for searching restaurants by zip code.

5. Component State:
   ```
   const [zipCode, setZipCode] = useState('');
   const [restaurants, setRestaurants] = useState([]);
   ```
   - `useState` is used to define two pieces of component state: `zipCode` and `restaurants`.
   - `zipCode` stores the user's input for the zip code.
   - `restaurants` will store the search results.

6. `handleSearch` Function:
   ```
   const handleSearch = () => {
     if (zipCode.trim() !== '') {
       // API request to search for restaurants based on the provided zip code
       // ...
     }
   };
   ```
   - `handleSearch` is a function that is called when the user clicks the "Search" button.
   - It first checks if the `zipCode` is not empty.
   - If the `zipCode` is not empty, it makes an API request to search for restaurants based on the provided zip code.

7. Making the API Request:
   ```
   api.get('/restaurants', {
     params: {
       where: { zipCode }, // Send the zipCode as a query parameter
     },
   })
     .then(response => {
       // Handle the API response
       // ...
     })
     .catch(error => console.error('Error searching restaurants:', error));
   ```
   - Axios is used to make a GET request to the `/restaurants` endpoint of the backend API.
   - It includes a query parameter `where` with the specified `zipCode`.
   - If the request is successful, the response is processed in the `.then` block, and the search results are updated in the `restaurants` state.
   - If there's an error, it is caught and logged in the `.catch` block.

8. Rendering the UI:
   - The component returns a JSX structure for rendering the search form, search button, and search results.
   - The search results are displayed as a list of restaurants if there are any.

That's a breakdown of the `SearchForm.js` code. It defines a React component for searching restaurants by zip code and requests API to retrieve restaurant data based on user input.

You can look into the final code of `searchForm.js`: [https://github.com/souravjain540/restaurant-finder-frontend/blob/main/src/components/searchForm.js](https://github.com/souravjain540/restaurant-finder-frontend/blob/main/src/components/searchForm.js)
 
### Create a RestaurantForm Component

Now, let's create a component for adding new restaurants. Create a file named `RestaurantForm.js` inside the src folder. This component will allow users to input restaurant details and submit them to the backend. Let's break down the code snippet of `RestaurantForm.js` step by step:

1. Import Statements:
   ```
   import React, { useState } from 'react';
   import axios from 'axios';
   ```
   - The code begins with importing the necessary modules.
   - `React` is imported to define React components.
   - `useState` is a React hook used to manage component-level state.
   - `axios` is imported to make HTTP requests to the backend API.

2. `getAuthToken` Function:
   ```
   const getAuthToken = () => {
     // Replace this with your logic to obtain the token
     return 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....'; // A placeholder token
   };
   ```
   - `getAuthToken` is a function that should be replaced with your actual logic to obtain an authentication token.
   - In this code, it returns a placeholder token.

3. Axios Configuration:
   ```
   const api = axios.create({
     baseURL: 'http://localhost:3000/api', // Adjust the base URL to your API endpoint
     headers: {
       'Content-Type': 'application/json',
       Authorization: `Bearer ${getAuthToken()}`, // Attach the token here
     },
   });
   ```
   - `api` is an instance of Axios configured with a base URL for the backend API.
   - It sets the `Content-Type` header to indicate that the request body is in JSON format.
   - It also attaches an authorization header with the token obtained from `getAuthToken`.

4. `RestaurantForm` Component:
   ```
   function RestaurantForm({ onFormSubmit }) {
     // ...
   }
   ```
   - `RestaurantForm` is a React functional component that takes a prop named `onFormSubmit`.
   - Inside this component, we will create the UI for adding a new restaurant.

5. Component State:
   ```
   const [name, setName] = useState('');
   const [address, setAddress] = useState('');
   const [zipCode, setZipCode] = useState('');
   const [phone, setPhone] = useState('');
   ```
   - `useState` is used to define four pieces of component state: `name`, `address`, `zipCode`, and `phone`.
   - These states will store the user's input for the restaurant's name, address, zip code, and phone number.

6. `handleFormSubmit` Function:
   ```
   const handleFormSubmit = (e) => {
     e.preventDefault();
  
     const newRestaurant = {
       name,
       address,
       zipCode,
       phone,
     };
  
     api.post('/restaurants', newRestaurant)
       .then(response => {
         // Call the onFormSubmit function with the newly created restaurant
         onFormSubmit(response.data);
  
         // Clear the form input fields
         setName('');
         setAddress('');
         setZipCode('');
         setPhone('');
  
         // Refresh the page after a successful submission
         window.location.reload();
       })
       .catch(error => console.error('Error creating restaurant:', error));
   };
   ```
   - `handleFormSubmit` is a function that is called when the user submits the restaurant form.
   - It first prevents the default form submission behavior.
   - It creates a `newRestaurant` object with the values entered in the form fields.
   - It makes a POST request to the `/restaurants` endpoint of the backend API to create a new restaurant.
   - If the request is successful, it calls the `onFormSubmit` function with the newly created restaurant data.
   - It also clears the form input fields, and then refreshes the page to reflect the updated restaurant list.
   - If there's an error, it is caught and logged.

7. Rendering the UI:
   - The component returns a JSX structure for rendering the restaurant form.
   - The form includes fields for entering the restaurant's name, address, zip code, and phone number.
   - When the user submits the form, the `handleFormSubmit` function is called.

That's a breakdown of the `RestaurantForm.js` code. It defines a React component for adding a new restaurant to the system, and it makes an API request to create the restaurant on form submission.

You can view the whole code here: [https://github.com/souravjain540/restaurant-finder-frontend/blob/main/src/components/restaurantForm.js](https://github.com/souravjain540/restaurant-finder-frontend/blob/main/src/components/restaurantForm.js)

### Creating the restaurantLists component:

Next, create a file named `RestaurantList.js` inside the src folder. This component will display the list of restaurants returned by the search. Let's break down the code snippet of `RestaurantList.js` step by step:

1. Import Statements:
   ```
   import React, { useState, useEffect } from 'react';
   import axios from 'axios';
   ```
   - The code begins with importing the necessary modules.
   - `React` is imported to define React components.
   - `useState` and `useEffect` are React hooks used to manage component-level state and side effects.
   - `axios` is imported to make HTTP requests to the backend API.

2. `getAuthToken` Function:
   ```
   const getAuthToken = () => {
     // Replace this with your logic to obtain the token
     return 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....'; // A placeholder token
   };
   ```
   - `getAuthToken` is a function that should be replaced with your actual logic to obtain an authentication token.
   - In this code, it returns a placeholder token.

3. Axios Configuration:
   ```
   const api = axios.create({
     baseURL: 'http://localhost:3000/api', // Adjust the base URL to your API endpoint
     headers: {
       'Content-Type': 'application/json',
       Authorization: `Bearer ${getAuthToken()}`, // Attach the token here
     },
   });
   ```
   - `api` is an instance of Axios configured with a base URL for the backend API.
   - It sets the `Content-Type` header to indicate that the request body is in JSON format.
   - It also attaches an authorization header with the token obtained from `getAuthToken`.

4. `RestaurantList` Component:
   ```
   function RestaurantList() {
     // ...
   }
   ```
   - `RestaurantList` is a React functional component that displays a list of restaurants.
   - Inside this component, we will fetch the list of restaurants from the backend and display them.

5. Component State:
   ```
   const [restaurants, setRestaurants] = useState([]);
   ```
   - `useState` is used to define a state variable `restaurants` that will store the list of restaurants fetched from the API.

6. Fetching Restaurants:
   ```
   useEffect(() => {
     api.get('/restaurants')
       .then(response => {
         setRestaurants(response.data);
       })
       .catch(error => console.error('Error fetching restaurants:', error));
   }, []);
   ```
   - The `useEffect` hook is used to fetch the list of restaurants when the component mounts (i.e., when it first renders).
   - It makes a GET request to the `/restaurants` endpoint of the backend API.
   - When the response is received, it sets the `restaurants` state with the data.

7. Deleting Restaurants:
   ```
   const handleDelete = (restaurantId) => {
     api.delete(`/restaurants/${restaurantId}`)
       .then(() => {
         // Filter out the deleted restaurant
         setRestaurants(restaurants.filter(restaurant => restaurant.id !== restaurantId));
       })
       .catch(error => console.error('Error deleting restaurant:', error));
   };
   ```
   - The `handleDelete` function is called when a user clicks the "Delete" button next to a restaurant.
   - It makes a DELETE request to the `/restaurants/{restaurantId}` endpoint of the backend API to delete the restaurant.
   - After successful deletion, it updates the `restaurants` state by filtering out the deleted restaurant.

8. Rendering the UI:
   - The component returns a JSX structure for rendering the list of restaurants.
   - It maps over the `restaurants` array and displays each restaurant's name, address, phone number, and zip code.
   - A "Delete" button is provided for each restaurant, which triggers the `handleDelete` function when clicked.

That's a breakdown of the `RestaurantList.js` code. It defines a React component for displaying a list of restaurants fetched from the backend and provides the ability to delete restaurants.

Find the complete code snippet here: [https://github.com/souravjain540/restaurant-finder-frontend/blob/main/src/components/restaurantList.js](https://github.com/souravjain540/restaurant-finder-frontend/blob/main/src/components/restaurantList.js)


### Changing the App.js file: 

Let's break down the code snippet of `App.js` step by step:

1. Import Statements:
   ```
   import React from 'react';
   import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
   import RestaurantList from '/Users/sauravjain/projects/my-restaurant-app/src/components/restaurantList.js';
   import RestaurantForm from '/Users/sauravjain/projects/my-restaurant-app/src/components/restaurantForm.js';
   import SearchForm from '/Users/sauravjain/projects/my-restaurant-app/src/components/searchForm.js';
   import '/Users/sauravjain/projects/my-restaurant-app/src/index.css'; // Import the CSS file
   ```
   - The code begins with importing the necessary modules and components.
   - `React` is imported to define React components.
   - `BrowserRouter`, `Routes`, and `Route` are imported from `react-router-dom` for defining and handling routes in the application.
   - `RestaurantList`, `RestaurantForm`, and `SearchForm` are imported as components from their respective file paths.
   - The CSS file is imported to apply styles to the application.

2. `App` Component:
   ```
   function App() {
     // ...
   }
   ```
   - `App` is a React functional component that serves as the main component for the application.
   - Inside this component, you define the routes, layout, and functionality of the app.

3. Event Handlers:
   ```
   const handleSearch = (searchResults) => {
     // Handle the search results (e.g., update state)
     console.log('Search results:', searchResults);
   };
   const handleFormSubmit = (newRestaurantData) => {
     // Update the state with the new restaurant data
     console.log('Restaurant data: ', newRestaurantData);
   };
   ```
   - Two event handler functions, `handleSearch` and `handleFormSubmit`, are defined. These functions are used to handle data received from child components.
   - `handleSearch` is intended to handle search results data, and `handleFormSubmit` is intended to handle new restaurant data.

4. Router Setup:
   ```
   return (
     <Router>
       <div className="App">
         <h1>Restaurant Finder</h1>
         
         <Routes>
           <Route path="/" element={<SearchForm onSearch={handleSearch} />} />
           <Route path="/restaurants" element={<RestaurantList />} />
           <Route path="/restaurants/add" element={<RestaurantForm onFormSubmit={handleFormSubmit} />} />
           <Route path="/restaurants/edit/:id" element={<RestaurantForm />} />
         </Routes>
       </div>
       <footer>
         {/* Footer content */}
       </footer>
     </Router>
   );
   ```
   - The `Router` component is used to wrap the entire application, enabling client-side routing.
   - Inside the router, there is a `div` with the class name "App" that serves as the main container for the application.
   - The `h1` element displays the title "Restaurant Finder."

5. Routes Configuration:
   - Inside the `Routes` component, different routes are defined using the `Route` component from `react-router-dom`.
   - The routes specify which components to render when certain URLs are accessed.

6. Route Paths and Components:
   - `/` path is associated with the `SearchForm` component. The `onSearch` prop is passed to it, allowing it to handle search results.
   - `/restaurants` path is associated with the `RestaurantList` component.
   - `/restaurants/add` path is associated with the `RestaurantForm` component. The `onFormSubmit` prop is passed to it to handle form submissions.
   - `/restaurants/edit/:id` path is associated with the `RestaurantForm` component, presumably for editing restaurant data.

7. Footer Section:
   - Below the `Router` content, there is a footer section with links to the author's Twitter profile and a mention of "Backend Powered by Amplication."

This is an overview of the `App.js` code, which sets up the routing and components for your restaurant finder application. It defines how different components are rendered based on the URL paths and handles events with the defined event handler functions.

Have a look at the final code snippet of the `App.js` file here: [https://github.com/souravjain540/restaurant-finder-frontend/blob/main/src/App.js](https://github.com/souravjain540/restaurant-finder-frontend/blob/main/src/App.js)

In the end, I encourage everyone to create the frontend by themselves according to their creativity, but if you want to have it like mine, please copy the [index.html](https://github.com/souravjain540/restaurant-finder-frontend/blob/main/public/index.html) and [index.css](https://github.com/souravjain540/restaurant-finder-frontend/blob/main/public/index.html) file as well.

In the end, your app will look like this:

#### Root directory(searchForm): 

<div>
<img src="https://static-assets.amplication.com/blog/creating-a-restaurant-finder-full-stack-web-application-using-reactjs-and-amplication/5.png" alt="" style="margin-left: auto; margin-right: auto;" height="943" width="1910">
</div>
<br />

#### restaurantLists.js:


<div>
<img src="https://static-assets.amplication.com/blog/creating-a-restaurant-finder-full-stack-web-application-using-reactjs-and-amplication/6.png" alt="" style="margin-left: auto; margin-right: auto;" height="943" width="1910">
</div>
<br />

#### restaurantForm.js

<div>
<img src="https://static-assets.amplication.com/blog/creating-a-restaurant-finder-full-stack-web-application-using-reactjs-and-amplication/7.png" alt="" style="margin-left: auto; margin-right: auto;" height="943" width="1910">
</div>
<br />

You can have a look at the complete frontend code here: [https://github.com/souravjain540/restaurant-finder-frontend/tree/main](https://github.com/souravjain540/restaurant-finder-frontend/tree/main)

If you have any problem with any part of this tutorial, please feel free to contact me on my [Twitter account](https://twitter.com/Sauain). Thanks for giving it a read.