Build a full-stack application with Amplication
Tags: webdev, javascript, amplication
Published: 2022-11-24 00:46:04

by [Ekekenta Odionyenfe Clinton](https://blog.openreplay.com/authors/ekekenta-odionyenfe-clinton)


Amplication is a versatile open-source Node.js app development platform that allows you to quickly create a production-ready Node.js backend without wasting time on repetitive coding. Furthermore, a pre-built UI or CLI simplifies the creation of data models and role-based access configuration. You can use Amplication to push your generated Application to GitHub, providing you with a containerized Node.js Typescript database application and a React client. NestJS, Prisma, REST, GraphQL API, React Admin UI, logging, user authentication, and authorization are all configured in all applications. It also enables developers to host applications on their servers using a Docker container or the Amplication cloud.

To get started building applications with Amplication, ensure you have the following installed:
- [Node.js](https://nodejs.org/en/) version 14 or later
- [PostgreSQL](https://www.postgresql.org/) database
- Prisma CLI (`npm install -g @prisma/cli`)
- Nestjs CLI (`npm install @nest/cli`)


## Create the backend
Once the above requirements are met, let's start by creating the backend part of our blog application. To begin, create an Amplication account to sign in to your dashboard if this is the first time you've done that.

Click the **+ Add New project** button on your Amplication home page to create a new project.

![1](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image01.png)

Then enter the project name. For example, we'll name the Application **BlogApp** for this demonstration and press the **Create Project** button.

![2](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image02.png)

###  Create a Blog Entity
To create an entity in an Amplication project, first, you need to create a service. To do that, click the **Add Resources** button and select **Service**.

![3](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image03.png)

Now on the create resource page, check the features you'd want in your project. We'll leave all the features contained for this demonstration and then click the **Create Service** button.

![4](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image04.png)

In the above selection, we are adding the feature for **GraphQL API**, **REST API & Swagger UI**, and **Admin UI** to our project. We also specified that we want to create entities by checking **None** on the Sample Entities option.

Now you'll be redirected to the Service dashboard.

![5](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image05.png)


Next, click the **Go to entities** button in the **Entities** tab. The Application already has a **User** entity for you by default. So click on the Add Entity button to create a **Blog** entity to store our blog data. Enter the Entity name and press the **Create Entity** button.

![6](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image06.png)

Right here, you are provided with some input boxes to allow you to define the fields of your Entity. For example, we'll create **name**, **description**, and **content** fields for our' Blog' entity.

![7](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image07.png)


### Add Permissions to Entity
Now let's add permissions to our Blog entity. By default, the Amplication entity has CRUD permission, but you can decide to grant permissions to a specific user or user role. For this demonstration, we'll give a **public** access to the Blog Entity so we can test things out to know how it works.

So, click on the **Permissions** and check the public box for all the services.

![8](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image08.png)

### Build the Application
Now enter your commit message and commit the changes by clicking the **Commit changes and build** button.

![9](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image09.png)

Once the commit is completed, click on the last commit number to download the source code for the project.

![10](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image10.png)

Once the download is completed, unzip the downloaded file. You'll have a **server** and **admin-ui** folders. Open the server folder in your favorite IDE.

### Create Custom Endpoints
By default, Amplication creates all the CRUD endpoints for all the entities in the Application. But the authentication module creates the login endpoint, so we need to modify the server to make a custom endpoint for the signup route. To do that, update the `AuthService` in the `server/src/auth/auth.service.ts` with the code snippet below.

```
//...
async signup(credentials: Credentials): Promise<UserInfo> {
    // Extract the username and password from the body of the request
    const { username, password } = credentials;
    // Here, we attempt to create a new user
    const user = await this.user service.create({
      data: {
        username,
        password,
        roles: [],
      },
    });
    // If creating a new user fails, throw an error
    if (!user) {
      throw new UnauthorizedException("Could not create user");
    }
    // Create an access token for the newly created user
    const accessToken = await this.tokenService.createToken({
      id: user.id,
      username,
      password,
    });
    // Return the access token as well as some details about the user
    return {
      accessToken,
      username: user.username,
      id: user.id,
      roles: []
    };
 }
 //...
```
In the above code snippet, we added a signup method to allow users to create an account. This function will take the user's credentials as a parameter and return a promise of type `UserInfo`. Once the user is created, we'll generate an access token for the user to allow them to log in to the Application.

Then update the `AuthController` in the `server/src/auth/auth.controller.ts` file with the code snippet below.

```
//...
 @Post("signup")
  async signup(@Body() body: Credentials): Promise<UserInfo> {
    return this.authService.signup(body);
  }
//...
```
In the above code, we added a signup route handler to use the signup method we created in the `AuthService` and accept the user input from the request payload.

Next, update the `AuthMutation` class in the `server/src/auth/auth.resolver.ts` file to crate a GraphQL **mutation** for the **AuthService** signup method.

```
//...
 @Mutation(() => UserInfo)
  async signup(@Args() args: LoginArgs): Promise<UserInfo> {
    return this.authService.signup(args.credentials);
  }
//...
```


### Run the Application
Now let's test out our Application's server and Admin UI. To run the server, run the command below to run the Docker container for the default PostgreSQL connection created for your Application.

```
npm run docker:DB
```

Then run the commands below to generate the Prisma client and create the schema for the database.

```
npm run Prisma:generate
npm run DB:init
```

Now start the Application with the command below.

```
npm run start
```


Then to start the Admin UI, move into the admin-UI folder and start the admin with the command below.

```
cd ../admin-UI
npm run start
```
You should see the login page, where you can choose which way to access or manipulate your Application's data.

![11](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image11.png)

So go ahead and use GraphQL, Admin UI, or Swagger to add blog data to your Application.

<h2>Open Source Session Replay</h2> 

_<a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a> is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data._

![OpenReplay](https://blog.openreplay.com/banner-blog_1oYPGT.png)

_Start enjoying your debugging experience - <a href="https://github.com/openreplay/openreplay" >start using OpenReplay for free</a>._



## Create the frontend
At this point, our backend has been fully configured. So, let's set up the frontend part of our Application. 

To get started, create a new react application with the command below.

```
npx create-react-app app
```

Once the installation is completed, install `axios` to allow us to make API requests to the backend with the command below.

```
npm i axios
```

Then start the Application by running the command below.

```
npm run start
```
### Create the UI components
Now let's create the components UI for our Application. First, generate the **components** folder in the **src** directory. Then in the components folder, create an `Auth.js` file for the authentication UI with code snippets below.

```javascript
export const Auth = ({ setActiveUser }) => {

  return (
    <div className="auth-container">
      <div className="auth-wrapper">
        <div className="login">
          <form>
            <h4>Login Here</h4>
            <input type="text" placeholder="username"/>
            <input type="text" placeholder="password"/>
            <button>Login</button>
          </form>
        </div>
        <div className="signup">
          <form>
            <h4>Signup Here</h4>
            <input
              type="text"
              placeholder="first name."
            />
            <input
              type="text"
              placeholder="last name."
            />
            <input
              type="text"
              placeholder="username"
            />
            <input
              type="text"
              placeholder="password"
            />
            <button>Signup</button>
          </form>
        </div>
      </div>
    </div>
  );
};

```

Then update the `App.js` file to render the **Auth** component with the code snippet below.

```javascript
//...
import { Auth } from "./components/Auth";
function App() {
  return (
    <div className="App">
        <Auth/>
    </div>
  );
}

export default App;
```
Now copy this Application's styles from the GitHub [repository](https://github.com/icode247/Amplication-blogApp/blob/main/server/style.css) and update the styles in the `App.css` file. So you open the Application on your browser, you'll see the output below:

![12](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image12.png)


Next, I created a `Header.js` file in the components folder to render the navbar of the Application with the code snippet below.

```javascript
export const Header = ({ setActiveUser }) => {
  return (
    <div className="nav">
      <ul>
        <li>
          <p>Home</p>
        </li>
        <li>
          <p>Contact Us</p>
        </li>
        <li>
          <p className="logout">
            logout
          </p>
        </li>
      </ul>
    </div>
  );
};
```
Then, create a `Blog.js` file in the components folder to render the blogs from our backend API.

```javascript
export const Blog = () => {
  return (
    <div>
        <div className="wrapper">
          <p className="header">Blog Name</p>
          <p className="content">Blog content</p>
          <p className="leesmeer">Read More</p>
        </div>
      ))}
    </div>
  );
};
```

Now render the Header and Blog components in the `App.js` file with code snippets below.

```javascript
///...
import { Blog } from "./components/Blog";
import { Header } from "./components/Header";
import { useState } from "react";

function App() {
  const [activeUser, setActiveUser] = useState(false);
  return (
    <div className="App">
      {activeUser ? (
        <>
          <Header setActiveUser={setActiveUser}/>
          <Blog />
        </>
      ) : (
        <Auth setActiveUser={setActiveUser} />
      )}
    </div>
  );
}

export default App;
```
In the above code snippet, we created an `activeUser` state variable to check if a user is logged in to render the **Header** and **Blog** components, else the **Auth** component.

### Consume the backend APIs 
Now let's consume the backend APIs to **signup**and **login** a user and to fetch the Blog from and render to the **Blog **component. First, let's start with the Auth component and update the `component/Auth.js` file with the code snippets below.

```javascript
import axios from "axios";
import { useState } from "react";

export const Auth = ({ setActiveUser }) => {
  const [firstname, setFirstname] = useState();
  const [lastname, setLastname] = useState();
  const [username, setUsername] = useState();
  const [password, setPassword] = useState();

  const signup = async (e) => {
    e.preventDefault();
    const res = await axios.post("http://localhost:3000/api/signup", {
      firstname,
      lastname,
      username,
      password,
    });

    if (res.data) {
      localStorage.setItem("accessToken", res.data.accessToken);
      setActiveUser(res.data);
    }
  };

  const login = async (e) => {
    e.preventDefault();
    const res = await axios.post("http://localhost:3000/api/login", {
      username,
      password,
    });

    if (res.data) {
      localStorage.setItem("accessToken", res.data.accessToken);
      setActiveUser(res.data);
    }
  };
  return (
    <div className="auth-container">
      <div className="auth-wrapper">
        <div className="login">
          <form onSubmit={login}>
            <h4>Login Here</h4>
            <input type="text" placeholder="username"  onChange={(e) => setUsername(e.target.value)}/>
            <input type="text" placeholder="password"  onChange={(e) => setPassword(e.target.value)}/>
            <button>Login</button>
          </form>
        </div>
        <div className="signup">
          <form onSubmit={signup}>
            <h4>Signup Here</h4>
            <input
              type="text"
              placeholder="firstname"
              onChange={(e) => setFirstname(e.target.value)}
            />
            <input
              type="text"
              placeholder="lastname"
              onChange={(e) => setLastname(e.target.value)}
            />
            <input
              type="text"
              placeholder="username"
              onChange={(e) => setUsername(e.target.value)}
            />
            <input
              type="text"
              placeholder="password"
              onChange={(e) => setPassword(e.target.value)}
            />
            <button>Signup</button>
          </form>
        </div>
      </div>
    </div>
  );
};
```
In the above code snippet, we imported the **axios** package we installed earlier and created a state variable for the inputs we send to the backend. Then we started two functions to handle the signup and login operations. In both functions, we used Axios to make an API request to the `http://localhost:3000/api/login` and `http://localhost:3000/api/signup` endpoints. Once the request is successful, we update the active user state and save the user's token in the local storage.

Next, update the `Blog.js` file to get the blogs from the backend with the code snippets below.

```javascript
import { useEffect, useState } from "react";
import axios from "axios";

export const Blog = () => {
  const accessToken = localStorage.getItem("accessToken");
  const [blogs, setBlogs] = useState([]);
  useEffect(() => {
    const getBlogs = async () => {
      const res = await axios.get("http://localhost:3000/api/blogs", {
        headers: {
          'Authorization': `Bearer ${accessToken}`,
        },
      });
      if (res.data) {
        setBlogs(res.data);
      }
    };

    getBlogs();
  }[accessToken]);
  return (
    <div>
      {blogs && blogs.map((blog) => (
        <div className="wrapper" key={blog.id}>
          <div className="pic"></div>
          <p className="header">{blog.name}</p>
          <p className="content">{blog.content}</p>
          <p className="leesmeer">Read More</p>
        </div>
      ))}
    </div>
  );
};
```
Here we sent a request to the `http://localhost:3000/api/blogs` endpoint using Axios, and when data is fetched from the request, we store them in the blogs state variable. In our request headers, we add the following. Then we loop through the Blog and render them to the users.

Lastly, update the code in the **Header** component to implement a logout functionality with the code snippet below.

```javascript
export const Header = ({ setActiveUser }) => {
  const logout = () => {
    localStorage.clear();
    setActiveUser("");
  };
  return (
    <div className="nav">
      <ul>
        <li>
          <p>Home</p>
        </li>
        <li>
          <p>Contact Us</p>
        </li>
        <li>
          <p className="logout" onClick={logout}>
            logout
          </p>
        </li>
      </ul>
    </div>
  );
};
```

So if you refresh the Application and sign up or log in, you'll see the Blog components with blogs you have created from the admin UI, as shown below.

![13](https://blog.openreplay.com/images/build-a-full-stack-application-with-amplication/images/image13.png)

## Conclusion
Amplication is an excellent tool for building a web application with minimal backend code. Feel free to check out other features of Amplication [documentation](https://amplication.com/).

In this article, we've explored how to build a full-stack blog application using Amplication. We started with a detailed explanation of what it is. Then went to creating a React frontend for the UI and consuming the backend APIs. I hope you enjoyed this article! Happy coding!

> A TIP FROM THE EDITOR: On the topic of using containers to deploy your site, don't miss our [Dockerizing Full-Stack React Apps](https://blog.openreplay.com/dockerize-full-stack-react-apps/) article.




[![newsletter](https://blog.openreplay.com/newsletter_Z1P0UIP.png)](https://newsletter.openreplay.com/)