Construction du site elleXX

elleXX est un site web destinĂ© Ă  aider les femmes Ă  joindre les deux bouts. Il a Ă©tĂ© crĂ©Ă© par des journalistes qui Ă©crivent de nombreux contenus utiles sur le sujet. En tant que femme en Suisse, je suis particuliĂšrement sensible Ă  cette problĂ©matique, d’autant qu’elle est trĂšs proche des valeurs de Liip. La principale tĂąche du site elleXX Ă©tait de permettre la publication rapide et simple de contenus. Il a aussi fallu prĂ©voir l’intĂ©gration de certains produits conçus pour faciliter la gestion financiĂšre, ainsi que le suivi des membres.

Pour la gestion de contenu, nous avons choisi de travailler avec le CMS Ghost. Une dĂ©cision qui n’est pas le fruit du hasard, car Ghost est vraiment trĂšs adaptĂ© Ă  ce dont nous avions le plus besoin : le contenu. D’autre part, Ghost est entiĂšrement financĂ© par ses utilisateurs∙rices, c’est un CMS open source !

Pour assurer le suivi des leads et des contacts, nous avons optĂ© pour Friendly Automatic. Pour une simple et bonne raison : c’est une entreprise suisse locale, reposant qui plus est sur Mautic, un framework bien connu pour les solutions marketing.

Il nous a aussi fallu intĂ©grer des outils propres au client, Ă  savoir Vontobel, MigrosBank et Cap Rechtsschutz. Pour cela, nous avons conçu notre propre API Ă  l’aide du framework JS Nest.js. Avec Nest.js, la crĂ©ation d’une API est simple et rapide. Nous autres dĂ©veloppeur∙euses pouvons ainsi nous concentrer davantage sur la logique de l’API que sur la conception du routing etc. Nous avons ensuite utilisĂ© notre API depuis notre instance Ghost.

Lorsqu’est venu le temps de personnaliser les fonctionnalitĂ©s du site, Ghost n’a pas Ă©tĂ© aussi flexible que nous l’aurions souhaitĂ©. Nous avons donc dĂ» forker Ghost et peaufiner notre propre version. Le client voulait par exemple simplifier et uniformiser l’affichage de certains contenus. En gĂ©nĂ©ral, on essaie plutĂŽt d’éviter d’avoir Ă  crĂ©er un fork d’un code source, mais cette opĂ©ration nous a permis de gagner Ă©normĂ©ment en flexibilitĂ©.

Conception de l’API REST avec Nest.JS

Nest est un framework Node.js qui permet de crĂ©er facilement des applications serveur Ă©volutives. Personnellement, je suis une dĂ©veloppeuse PHP, mais j’ai choisi Nest plutĂŽt que PHP car l’équipe avec laquelle j’allais travailler Ă©tait plus familiĂšre de JavaScript. Lorsque je choisis une technologie, je cherche d’abord celle qui sera la plus simple d’utilisation pour les personnes qui seront chargĂ©es de travailler avec. ET nous sommes trĂšs heureux∙euses d’avoir optĂ© pour ce framework ! GrĂące Ă  lui, la crĂ©ation de l’API a Ă©tĂ© une vraie partie de plaisir.

Nest est divisĂ© en modules. Chaque module dispose de sa propre configuration mais aussi de ses propres contrĂŽleurs et services / fournisseurs. Dans le cadre de notre projet, nous avons dĂ©cidĂ© de crĂ©er un module pour chaque intĂ©gration, c’est-Ă -dire un module Vontobel, un module MigrosBank et un module Cap Rechtsschutz. Nous avons Ă©galement ajoutĂ© certains autres modules dont nous avions besoin, tels que « Auth », « Mail », « Ghost », « Customer »...

Voici un contrÎleur entier que nous avons construit dans Nest pour créer un nouveau membre Ghost:

import { Controller, Post, Body, Get } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { GhostService } from './ghost.service';

@Controller('ghost')
@ApiTags('ghost')
export class GhostController {
  constructor(private readonly ghostService: GhostService) {}

  @Post('new')
  async newMember(@Body() body): Promise<any> {
    return this.ghostService.getGhostMemberUuidFromEmailCreateNewMemberIfNotExists(
      body.firstname,
      body.email,
    );
  }
}

Dans Nest, on utilise de nombreuses annotations qui facilitent la programmation. À noter l’utilisation de @Controller, qui est un contrîleur @ApiTags, pour la documentation Open API, et de @Post pour le routage !

L’injection de code fonctionne grñce à la configuration dans le module :

import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { GhostController } from './ghost.controller';
import { GhostService } from './ghost.service';

@Module({
  imports: [HttpModule],
  controllers: [GhostController],
  providers: [GhostService],
})
export class GhostModule {}

On remarquera ici que nous avons le « GhostService » en tant que fournisseur. C’est un service que nous avons crĂ©Ă© nous-mĂȘmes. Le Ghost Service contient des mĂ©thodes pour communiquer avec Ghost. Nous nous en servons pour connecter les membres Ghost aux membres de l’API pour nos intĂ©grations, et pour ajouter des membres Ă  Friendly Automatic dĂšs leur inscription.

TypeScript est un langage de programmation entiĂšrement typĂ© qui permet en outre une superbe documentation avec Open API grĂące Ă  l’utilisation d’objets pour les rĂ©ponses API. Dans les objets, il suffit d’annoter les propriĂ©tĂ©s qu’Open API doit faire figurer dans la documentation :

@ApiProperty({
    required: true,
    description:
      'The id that the frontend calling the ellexx api is using to identify their user, is usually a unique identifier',
    example: 'sdfsd-23432-sfdfsd-2323',
  })
  public frontendId: string;

Setting up open api this way takes little effort but gives an invaluable documentation for API consumers.

Infrastructure

Pour l’hĂ©bergement, nous voulions une solution suisse et avons dĂ©cidĂ© d’utiliser Managed Kubernetes d’exoscale. Nous utilisons aussi Longhorn pour MySQL. Le recours Ă  Kubernetes pour notre projet est rĂ©solument exagĂ©rĂ© mais cela fonctionne Ă  la perfection. Nous utilisons Gitlab pour hĂ©berger notre code et Gitlab CI pour automatiser notre workflow. L’entrĂ©e d’un code gĂ©nĂšre la crĂ©ation et le dĂ©ploiement d’une image, pour le staging d’abord, puis pour la production. Notre solution Kubernetes prĂ©sente l’avantage d’ĂȘtre Ă©volutive. CEPENDANT, Ghost ne l’est pas. Pour un site Ghost Ă  trafic Ă©levĂ©, il faut rĂ©soudre le problĂšme en utilisant le cache http. Nous avons mis au point un cache Varnish tout simple, juste au cas oĂč. L’API en revanche est extensible. En raison de la nature dynamique des endpoints, nous n’avons pas vraiment pu tirer profit d’un cache ici.

Post Mortem

Ghost, Nest, Friendly Analytics, Gitlab, Gitlab CI, Kubernetes, MySQL avec Longhorn... avec le recul, changerions-nous quelque chose ? Non, pas vraiment ! Nous sommes rĂ©ellement satisfait∙e∙s de notre configuration. La seule chose que nous aurions Ă©ventuellement pu faire autrement, c’est d’utiliser Ghost en tant que headless CMS. Mais au bout du compte, tout a bien fonctionnĂ© et nous sommes tous∙tes trĂšs satisfait∙e∙s et fiers∙ùres du travail accompli.