Integrate Strapi on Nuxt
Tags: strapi, webdev, javascript, beginners
Published: 2024-01-28 17:30:11


## What is Strapi?

Strapi is a headless CMS, which means you can create your own API and distribute it without any constraints.

{% embed https://strapi.io/ %}

## Backend with Strapi

### Installing Strapi

Before installing the CMS, please make sure you have Node.js v20.

```bash
npx create-strapi-app@latest my-project
```

Or with yarn :


```bash
yarn create strapi-app my-project --quickstart
```

With this command, you will follow a simple process to install it. It couldn't be simpler. For the rest, we're using SQLite (by default) in this example, but you're free to install whatever database you want.


```bash
thomasbnt@thomasbnt:~/lab$ yarn create strapi-app my-project --quickstart
yarn create v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...

success Installed "create-strapi-app@4.19.0" with binaries:
      - create-strapi-app
Creating a quickstart project.
Creating a new Strapi application at /lab/my-project.
Creating files.
Dependencies installed successfully.
Initialized a git repository.

Your application was created at /lab/my-project.

Available commands in your project:

  yarn develop
  Start Strapi in watch mode. (Changes in Strapi project files will trigger a server restart)

  yarn start
  Start Strapi without watch mode.

  yarn build
  Build Strapi admin panel.

  yarn strapi
  Display all available commands.

You can start by doing:

  cd /lab/my-project
  yarn develop

Running your Strapi application.

> my-project@0.1.0 develop
> strapi develop

⠋ Building build context
⠙ Building build context[INFO] Including the following ENV variables as part of the JS bundle:
    - ADMIN_PATH
    - STRAPI_ADMIN_BACKEND_URL
    - STRAPI_TELEMETRY_DISABLED
✔ Building build context (100ms)
✔ Creating admin (10071ms)
⠸ Loading Strapi[2024-01-27 18:49:09.061] info: The Users & Permissions plugin automatically generated a jwt secret and stored it in .env under the name JWT_SECRET.
✔ Loading Strapi (2075ms)
✔ Generating types (320ms)

 Project information

┌────────────────────┬──────────────────────────────────────────────────┐
│ Time               │ Sat Jan 27 2024 18:49:10 GMT+0100 (Central Euro… │
│ Launched in        │ 2405 ms                                          │
│ Environment        │ development                                      │
│ Process PID        │ 19885                                            │
│ Version            │ 4.19.0 (node v20.2.0)                            │
│ Edition            │ Community                                        │
│ Database           │ sqlite                                           │
└────────────────────┴──────────────────────────────────────────────────┘

 Actions available

One more thing...
Create your first administrator 💻 by going to the administration panel at:

┌─────────────────────────────┐
│ http://localhost:1337/admin │
└─────────────────────────────┘

[2024-01-27 18:49:11.419] http: GET /admin (12 ms) 200
[2024-01-27 18:49:11.454] http: GET /admin/runtime~main.b145af60.js (6 ms) 200
[2024-01-27 18:49:11.463] http: GET /admin/main.5eaa19e8.js (2 ms) 200
[2024-01-27 18:49:11.827] http: GET /admin/project-type (2 ms) 200
[2024-01-27 18:49:11.846] http: GET /admin/6707.d7b87269.chunk.js (2 ms) 200
[2024-01-27 18:49:11.983] http: GET /admin/6538.27d4c381.chunk.js (3 ms) 200
[2024-01-27 18:49:11.984] http: GET /admin/9719.fe70b828.chunk.js (2 ms) 200
[2024-01-27 18:49:11.984] http: GET /admin/1025.2d854ef2.chunk.js (2 ms) 200
[2024-01-27 18:49:11.989] http: GET /admin/5019.0d8113a1.chunk.js (3 ms) 200
[2024-01-27 18:49:11.990] http: GET /admin/4944.c9cc5f7f.chunk.js (3 ms) 200
[2024-01-27 18:49:11.991] http: GET /admin/9170.6aa61d26.chunk.js (3 ms) 200
[2024-01-27 18:49:11.994] http: GET /admin/1727.8847f948.chunk.js (1 ms) 200
[2024-01-27 18:49:12.048] http: POST /admin/renew-token (9 ms) 400
[2024-01-27 18:49:12.051] http: GET /admin/init (16 ms) 200
[2024-01-27 18:49:12.054] http: GET /admin/users/me (18 ms) 401
[2024-01-27 18:49:12.144] http: GET /admin/3067.4f4141cb.chunk.js (1 ms) 200
[2024-01-27 18:49:12.149] http: GET /admin/telemetry-properties (2 ms) 401
[2024-01-27 18:49:12.354] http: GET /admin (2 ms) 200
[2024-01-27 18:49:12.588] http: GET /admin/project-type (1 ms) 200
[2024-01-27 18:49:12.686] http: GET /admin/init (2 ms) 200
[2024-01-27 18:49:12.811] http: GET /favicon.ico (0 ms) 200
```

You have [all the documentation available](https://docs.strapi.io/dev-docs/quick-start).

After installing everything and the dependencies, the server starts automatically as you can see above. However, if this has not been done, do `yarn develop`.

### Create your account on the dashboard

When you go to http://localhost:1337 for the first time, you will be asked to create a Super Admin account.

![Strapi registration page for the first Super Admin account with text fields such as first name, last name, email address and password](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dg4nyv3ixjt30tsh5kna.png)

Youhou! You've got access to Strapi! ✨🚀

![Strapi Dashboard with menu on the left and content in the centre](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ngx6y0yym50icyk8fexs.png)

### Creating the Collection

In this example, we're going to create a collection to display the latest updates from a Discord robot, so that we can display it wherever we want, in this case, on the website under Nuxt but also with a Slash command on the Discord platform through the robot!

Go to *Content-Type Builder* → _Collections Types_ → _Create new collection type_. 

![Creation of a type collection in Strapi](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xu8lx40w2a6o4sf2c5zw.png)

We're going to give it a proper name "ChangelogMrRobotApp" (here Mr. Robot refers to the name of the robot). Then create fields by clicking on the *Add new field.* button.
In my case, I simply want to display :

- The title
- The version
- The release date
- The content of the version
- The slug
- And a banner, which is optional

> **Caution**
> The date of creation and publication is ALREADY taken into account in Strapi, so there's no need to add this date field to your Collections!

Then we fill in all these fields in the *Content Manager* tab. Then we can move on to the front!

![Creating a sample collection in Strapi](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/blrihjvtutaxh5zdvzmh.png)

## Integration on the front end with Nuxt

I'm using Nuxt for the front end, because the robot's website uses this framework. But you're free to arrange it as you see fit. It's just a fetch request and some JavaScript.

### Creating the API token

Before continuing with the code, we're going to create an API Token, *Settings → API Tokens → Add new API Token*. What we want is simply to GET the Collection, without having any other permissions. It will allow us to retrieve information from the API. This token should be private. 

- Token type as "Read-only
- Token duration as "Unlimited
- And permissions only on "find" and "findOne" on the Collection

![Strapi page for creating a new API token, including name, description, token duration, type (read-only in this case) and permissions (here only the ChangelogMrRobotApp Collection)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vfmvsnva2diisa3g8yhd.png)

### Retrieving data with the call API

Now we can retrieve the data from the Collection from the Strapi API. Since the content is in Markdown, we need to perform an additional step, that of transforming the Markdown text into HTML. To do this, I'm using the `markdown-it` package.

#### First function: Fetch data from the API

Simply use `useFetch` from *Nuxt*. We get our data, and we can put it in a ref.

```js
const config = useRuntimeConfig();
let changelogs = ref([]);

await useFetch(`${config.public.backendStrapiUrl}changelogs-mr-robot-app?populate=*&sort[0]=version:desc`, {
  headers: {
    Authorization: `Bearer ${config.public.backendStrapiPublicAPIToken}`
  }
}).then((response) => {
  changelogs = response.data._value;
});
```

- Here, `config.public.backendStrapiUrl` contains the URL of Strapi with the endpoint API to retrieve the Collection of changelogs, populated ([see what the populate is](https://docs.strapi.io/dev-docs/api/rest/populate-select)) and sorted by version on the way down.
- And `config.public.backendStrapiPublicAPIToken`, as its name suggests, is your Token!

You get an array with everything you want. Magic!

#### Transforming Markdown content → HTML

With `markdown-it`, we'll be able to work even more magic. Install the package, and add it to the component/page.

```js
import MarkdownIt from "markdown-it";
const md = new MarkdownIt();

changelogs.data.forEach((changelog) => {
  changelog.attributes.content = md.render(changelog.attributes.content);
});

function formatDate(date) {
  const options = { year: "numeric", month: "long", day: "numeric" };
  return new Date(date).toLocaleDateString("fr", options);
}
```

I've added a function called `formatDate`, which simply sets the date to the correct format.

### Result on one page

And now... (drum roll 🥁)... you need to integrate this part into your HTML body!

```html
<article v-for="l in changelogs.data" :key="l.id" v-show="changelogs">
  <NuxtLink :to="'#' + l.attributes.slug">
    <h3 class="changelog_title" v-if="l.attributes.title" :id="l.attributes.slug">{{ l.attributes.title }}</h3>
  </NuxtLink>
  <div class="changelog_infos">
    <div
      v-if="l.attributes.releasedAt">
      <Icon name="lucide:calendar" />
      Sorti le {{ formatDate(l.attributes.releasedAt) }}
    </div>
    —
    <div v-if="l.attributes.version">v.{{ l.attributes.version }}</div>
  </div>
  <div v-html="l.attributes.content" v-if="l.attributes.content"></div>
</article>
```

With a little CSS, we render it with style, and here's the result!

![Result of the code with the changelogs, integrating the Strapi API call, and using the markdown-it package to transform markdown into HTML](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2044541gk4fwuo98q69b.png)

This web page is available on [mrrobot.app/changelog](https://mrrobot.app/changelog) if you're curious. 🚀

## Conclusion

I discovered Strapi quite a while ago. And I hadn't created anything with it, until I had a project, where I suggested it. I've loved it ever since. For its ease of use, its documentation, its API management, and above all, its ease of integration with any framework.


{% cta https://thomasbnt.dev/blog/integrer-strapi-sur-nuxt %} This post is available in French language → {% endcta %}