AccueilClientsExpertisesBlogOpen SourceJobsContact

19 juillet 2023

Directus : le CMS headless open source

7 minutes de lecture

Directus : le CMS headless open source

Dans le cadre d'une mission pour l'Office national de diffusion artistique, nous avons eu l'occasion de travailler avec le CMS headless Directus. Nous avons été séduits par sa simplicité d'utilisation et sa flexibilité. Nous vous proposons un retour sur les différents points techniques que nous avons aimés.

Open-source

Directus est un CMS headless (tel que Strapi) permettant de développer rapidement des backends/admin pour vos applications. Il offre une interface d'administration moderne et personnalisable, ainsi qu'une API REST / GraphQL pour consommer vos données.

L'un des points forts de Directus est d'être entièrement open-source. Directus propose une offre Cloud assez coûteuse (99$ par mois), mais aussi la possibilité d'héberger le CMS sans frais.

C'est bien sûr cette dernière option que nous avons choisie pour l'Onda afin d'avoir la main sur l'infrastructure et les coûts. Pour héberger Directus, il vous faudra une infrastructure classique permettant de faire tourner un serveur web Node.js.

Créer un projet

Initialiser un nouveau projet Directus est très simple grâce au CLI.

La commande init permet d'installer les dépendances, configurer votre base de données (infos stockées dans un fichier .env) et créer l'utilisateur admin :

npm init
npm add directus

npx directus init

? Choose your database client (Use arrow keys)
❯ PostgreSQL / Redshift
  CockroachDB (Beta)
  MySQL / MariaDB / Aurora
  SQLite
  Microsoft SQL Server
? Choose your database client PostgreSQL / Redshift
? Database Host: 127.0.0.1
? Port: 5432
? Database Name: directus
? Database User:
? Database Password:
? Enable SSL: (y/N)

Create your first admin user:

? Email xxx@xxxx.xx
? Password ****

Start Directus by running:
  npx directus start

Ceci fait, vous pouvez lancer Directus :

npx directus start

Workflow de développement

Création du modèle de données

À l'image d'un CMS headless, Directus permet de créer vos modèles de données très simplement via une interface :

Création d'une collection

Créons par exemple une collection articles avec différents champs :

Création des champs

Directus va alors créer une table articles dans votre base de données avec les champs que vous avez définis.

Table articles

Un des avantages de Directus est de bien séparer vos données métiers et les données de configuration liées à Directus (le fait que le champ content doit-être du type markdown par exemple). Ainsi tout ce qui est lié à Directus est stocké dans des tables préfixées par directus_.

Versionning du schéma

Lors du cycle de développement, il est important de versionner votre modèle de données afin que différents développeurs puissent récupérer les changements. Pour cela, Directus offre deux commandes pour exporter et importer des snapshots via un fichier yaml ou json :

npx directus schema snapshot ./snapshot.yaml
// snapshot.yaml
version: 1
directus: 12.0.3
vendor: postgres
collections:
  - collection: articles
    meta:
      accountability: all
      archive_app_filter: true
      archive_field: null
      archive_value: null
      collapse: open
      collection: articles
      color: null
      display_template: null
      group: null
      hidden: false
      icon: null
      item_duplication_fields: null
      note: null
      preview_url: null
      singleton: false
      sort: null
      sort_field: null
      translations: null
      unarchive_value: null
    schema:
      name: articles
// ...

Vous pouvez ainsi versionner ce schéma et récupérer les changements grâce à la commande apply :

npx directus schema apply ./snapshot.yaml

Cette commande doit aussi être lancée lors de vos déploiements (via un CI par exemple) afin de mettre à jour le schéma de votre base de données.

OpenAPI et TypeScript

Spécification OpenAPI

Qui dit CMS headless, dit frontend pour consommer les données. Ce front peut-être par exemple une application Next.js qui va se connecter à l'API de Directus pour récupérer vos données. Il est alors fort utile d'avoir un contrat fort de typage entre l'api et le front. Nous pouvons utiliser la spécification OpenAPI générée par Directus et créer les types TypeScript associés.

Directus expose la spécification à l'adresse suivante :

http://0.0.0.0:8055/server/specs/oas?access_token=VOTRE_TOKEN

openapi "3.0.1"
info	{}
servers	[]
paths	{}
tags []
components {}

Afin d'avoir accès à l'ensemble du schéma, il vous faudra générer un token statique depuis un utilisateur administrateur. On regrette le fait de ne pas pouvoir générer un token statique global sans passer par un utilisateur.

Il est important de relever que la spécification OpenAPI générée prend en compte les permissions liés au token. Ainsi sans token, si le rôle Public a seulement accès en lecture aux endpoints de lecture des articles, uniquement ces derniers seront retournés dans la spécification :

Rôles

On découvre par la même occasion la gestion très fine des rôles et permissions de Directus. Pour chaque rôle défini, nous pouvons définir les permissions CRUD sur chaque collection (et même aller sur une granularité plus fine grâce à un système de règles).

Typages avec TypeScript

Nous avons déjà évoqué le workflow de génération de types TypeScript depuis une spécification OpenAPI dans un précédent article.

Depuis votre front, vous pouvez utiliser la librairie swagger-typescript-api afin de générer les types associés à votre API :

swagger-typescript-api -p http://0.0.0.0:8055/server/specs/oas?access_token=VOTRE_TOKEN -o src/generated -n types.d.ts

Directus offre un SDK TypeScript pour facilement requêter votre API en utilisant vos types TS :

import { ItemsArticles } from '@/generated/types'
import { Directus } from '@directus/sdk'

type Collections = {
  articles: ItemsArticles
}

const directus = new Directus<Collections>(process.env.NEXT_PUBLIC_API_HOST)
const articles = await directus
  .items('articles')
  .readByQuery({ filter: { title: { _contains: 'Hello world' } } })

Next.js et génération statique

Le site de l'Onda est une application Next.js 13 qui vient consommer directement l'API exposée par Directus. Les pages sont générées statiquement lors du build puis sont regénérées automatiquement lorsque des changements sont détectés.

Un tel workflow peut être mis en place facilement avec le mécanisme de revalidation de Next.js ainsi que les flux webhooks de Directus.

Route d'API Next.js côté front pour regénérer une page :

import { revalidatePath } from 'next/cache'
import { NextRequest, NextResponse } from 'next/server'

export async function GET(request: NextRequest) {
  if (!request.url) {
    return new Response('Invalid request', { status: 400 })
  }

  const { searchParams } = new URL(request.url)

  const secret = searchParams.get('secret')
  const path = searchParams.get('path')

  if (!secret || secret !== process.env.INVALIDATE_SECRET_TOKEN || !path) {
    return new Response('Invalid credentials or missing path', {
      status: 400,
    })
  }

  revalidatePath(path)

  return NextResponse.json({
    revalidated: true,
    now: Date.now(),
  })
}

Mise en place d'un flux d'invalidation côté Directus :

Invalidation

Un système d'extensions complet

Directus offre également la possibilité d'étendre ses fonctionnalités grâce à un système d'extensions. Il est possible de créer plusieurs types d'extensions, parmi lesquels :

Cela permet de facilement étendre Directus pour répondre à des besoins spécifiques. À noter que Directus est développé en Vue.js : toutes les interfaces doivent donc être développées avec cette librairie. En tant qu'agence spécialisée en React, nous aurions aimé un binding agnostique et pouvoir développer nos interfaces avec React.

Nous avons aussi utilisé Prisma au sein des extensions de type serveur (endpoints, hooks, listeners…) afin de bénéficier d'un query builder TypeScript puissant. Grâce à la commande pull, nous pouvons récupérer le schéma et bénéficier du client Prisma :

prisma db pull
prisma generate

Derniers mots

Les points forts

Pour finir voici les autres points qui nous ont séduits dans Directus :

  • Un écosystème vivace : des releases régulières, une communauté active et une documentation de qualité ;
  • Un système de permissions complet : pour un rôle donné, il est possible de définir des permissions avec une granularité très fine ;
  • Une UX/UI de qualité : Directus est très agréable à utiliser et offre une UX moderne avec le souci du détail ;
  • Un haut niveau de personnalisation : grâce à de nombreuses options, il est possible de personnaliser l'interface de Directus pour répondre à vos besoins sans trop de développements custom ;
  • Un système de workflows : grâce à un outil no-code intégré, vous pouvez facilement mettre en place des workflows sur vos données métiers ;
  • Une gestion des traductions : gérer plusieurs langues dans vos collections est très simple avec Directus ;

Ce que nous aimons moins

  • Interfaces des extensions en Vue.js plutôt que React.js, mais c'est personnel 😁 ;
  • Des conflits GIT sur le fichier de snapshot du schéma parfois assez complexes à résoudre ;

Beaucoup de points positifs donc pour Directus : un outil que nous ajoutons à notre stack technique avec grand plaisir ! Nous pensons donc à l'avenir partir sur Directus plutôt que Strapi. En effet, Directus offre une meilleure UX/UI/DX, un écosystème plus mature et permet de mieux s'adapter aux règles métiers de nos clients.

18 avenue Parmentier
75011 Paris
+33 1 43 57 39 11
hello@premieroctet.com

Suivez nos aventures

GitHub
Twitter
Flux RSS

Naviguez à vue