# Build a Fullstack App With Strapi and Next.js

Let's build a fullstack blog using [Strapi](https://strapi.io/) and [Next.js](https://nextjs.org/). This article is based on [Digital Ocean's Tech Talk by Chris Sev](https://www.youtube.com/watch?v=WrmndNpWSJw). To get the ball rolling, let's setup our Strapi backend by running the following command in the terminal

```plaintext
npx create-strapi-app blog-strapi --quickstart
```

This command creates a Strapi project named *blog-strapi* and automatically opens the admin panel in our default browser. Let's go ahead and enter credentials and click *LET'S START*. We should see the Strapi dashboard as shown below

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/84qkgm3ax39hdxdwz932.PNG align="center")

Let's create our collection. On the dashboard, click on *CREATE YOUR YOUR FIRST CONTENT-TYPE*. Let's have *Post* as display name and click *Continue*. Select *Text* as the collection type and name the field *title* and leave the *Short text type* selected. Click on *Add another field* and select *Text* collection type and name it *slug*. Let's add one more field by clicking *Add another field*, select *Rich text* and name it *content* and click *finish* and *save*. Our collection now looks as below

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wmzxfs11vqok6rwgmblt.PNG align="center")

To create posts, go to the left panel under Collection types, click on *Posts* and hit the *Add New Posts* button. Let's add the title as *My Wins This Week*, slug as *my-wins-this-week*, content as *Won the golf tournament* and click *save* and *publish*. Head over to the browser at http://localhost:1337/posts. We should be getting a Forbidden error because the API is secured by default. To change that, let's get back to the Strapi dashboard and click on *settings*. Under *USERS AND PERMISSIONS PLUGIN*, click on *Roles* then public and select *find*, *findone*, *create* and click *save*. Let's get back to our browser and refresh http://localhost:1337/posts. We should see our post as shown below

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wfcwik2e9b60x8no2icb.PNG align="center")

Our post looks good so far but we have no idea who the author is. To be able to add an author, we need to add another field of type relation to the Post collection type. On the Strapi dashboard, click on *Content-Type Builder*, select *Post*, click on *Add another field* and select *Relation*. On the *File* dropdown select *User(from-users-permiss...)* and select a *User has many Posts* relation. Let's rename *users\_permissions\_user field name* to simply *user* and click *finish* and *save*. Let's go ahead and create a user. Under collection types, select *Users* and click on *Add New Users*. Input user credentials and toggle *Confirmed* button to set it to ON. Under *Posts(0)*, let's assign *My Wins This Week* post to this user(in my case daka) because why not? Click save and refresh the browser at http://localhost:1337/posts. You should see the user object included in our response as shown below

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/iqp75902wf08cawbji2y.PNG align="center")

Go ahead and create a couple of more posts and assign them users so that we have enough data to work with on the frontend.

Let's create our Next.js frontend by running the following command in the terminal

```plaintext
npx create-next-app blog-next
```

The above command creates a new Next.js app. Once the setup is done, run the following commands

```plaintext
cd blog-next
npm run dev
```

This will start our Next.js app server and the app can be accessed at http://localhost:3000/. Let's open up our app in a Text Editor(I'm using VS Code), go to `index.js` and replace everything in the return block with `<div>We are here!</div>` and save. Head over to the browser at http://localhost:3000 and we should see the output as shown below

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/b6nsq3rf78mx178rtg14.PNG align="center")

Let's go above the Home component and get our API data using [getStaticProps](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) function as shown below.

```plaintext
export async function getStaticProps() {
  //get posts from API
  const res = await fetch('http://localhost:1337/posts');
  const posts = await res.json();

  return {
    props: { posts }
  };
}
```

Now, in our Home component we can receive the posts as props and loop over them as shown below

```plaintext
export default function Home({ posts }) {
  return (
    <div className={styles.container}>
      {/* Loop over posts and show them */}
      {posts &&
        posts.map(post => (
          <div key={post.id} className={styles.post}>
            <h1>{post.title}</h1>
            <p>{post.content}</p>
            <em>By {post.user.username}</em>
          </div>
        ))}
    </div>
  );
}
```

Let's also add a bit of styling. In the `styles` directory, go to `Home.module.css` and replace all that is in there with the CSS code below.

```plaintext
.container {
  display: grid;
  grid-template-columns: auto auto auto;
  margin: 5%;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.post {
  padding-bottom: 10%;
}

```

When we save this, we should see the posts as shown below(of course you could do better styling).

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gqxmtodi3io5ha4yd7bf.PNG align="center")

Now let's handle routing by creating a file called `[slug].js` in the pages directory. This is a way that Next.js dynamically generates a bunch of files. There are two main things we need to do in `[slug].js`:

1.  Tell Next.js how many pages there are and
    
2.  For each individual page; get the data for that page.
    

We can achieve these with the help of [getStaticPaths](https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation) and [getStaticProps](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) functions respectively as shown in the snippet below

```plaintext
//Tell Next.js how many pages there are
export async function getStaticPaths() {
  const res = await fetch('http://localhost:1337/posts');
  const posts = await res.json();

  const paths = posts.map(post => ({
    params: { slug: post.slug }
  }));

  return {
    paths,
    fallback: false
  };
}

//For each individual page; get the data for that page
export async function getStaticProps({ params }) {
  const { slug } = params;
  const res = await fetch(`http://localhost:1337/posts?slug=${slug}`);
  const data = await res.json();
  const post = data[0];
  return {
    props: { post }
  };
}
```

[`fallback`](https://nextjs.org/docs/basic-features/data-fetching#the-fallback-key-required) in `getStaticPaths` is set to false because we have a small number of paths to pre-render - so they are all statically generated during build time. In `getStaticProps`, `const post` is assigned `data[0]` because the response we get is an array and we are only interested in the first element.

We can now add a Post component in `[slug].js` and pass the props as shown below

```plaintext
export default function Post({ post }) {
  return <div>{post.title}</div>;
}
```

Now when we route to http://localhost:3000/my-wins-this-week, we get a single post as shown below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/uhlheg0u6mryiwjju5o5.PNG align="center")

Awesome right?

So, to be able to generate our post files, we need to add the following script to our `package.json`

```plaintext
  "export": "next build && next export"
```

Let's stop the server and run it

```plaintext
npm run export
```

This generates HTML files from all the posts we have in Strapi. These files are in the `out` folder and are minified and ready to be hosted on a static server. Now we will add provision to navigate between the posts page and the single post page using the Next.js `Link`. Edit the return block of the Home component as shown below

```plaintext
<div className={styles.container}>
      {/* Loop over posts and show them */}
      {posts &&
        posts.map(post => (
          <Link href={`/${post.slug}`} key={post.id} className={styles.post}>
            <a>
              <h1>{post.title}</h1>
              <p>{post.content}</p>
              <em>By {post.user.username}</em>
            </a>
          </Link>
        ))}
    </div>
```

and the return block for the Post component in`[slug].js` as follows

```plaintext
    <div>
      <Link href="/">
        <a>Home</a>
      </Link>
      <h1>{post.title}</h1>
    </div>
```

Be sure to import `Link` from "next/link" in both cases. Now, when we start the server, we should be able to navigate through our site.

The last thing we want to do is creating a post. For that we need an API exploration tool, in my case I'm using [Postman](https://www.postman.com/). Let's create a POST request with the following body:

```plaintext
{
    "title": "The New Normal",
    "slug": "the-new-normal",
    "content": "The new normal is here",
    "user": {
        "id": 1
    }
}
```

When we hit send, below is the post response we are getting

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2huviavem3ut9gbvshdq.PNG align="center")

When we head over to our Strapi dashboard, we can see our new post added to the list of posts and when we click on it, we see the information passed as shown below.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/c30rcb89c0apkmsuhoo3.PNG align="center")

That's it, our basic fullstack app is done.

Happy coding!
