What is Strapi?
Strapi is a headless CMS, which means you can create your own API and distribute it without any constraints.
Backend with Strapi
Installing Strapi
Before installing the CMS, please make sure you have Node.js v20.
npx create-strapi-app@latest my-project
Or with yarn :
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.
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.
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.
Youhou! You've got access to Strapi! β¨π
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.
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!
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
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.
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) 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.
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!
<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!
This web page is available on 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.