Comprendre les usines, les luminaires et les sérialiseurs (partie 2) – Smashing Magazine


A propos de l’auteur

Kelvin Omereshone est le directeur technique de Quru Lab. Kelvin était auparavant ingénieur front-end chez myPadi.ng. Il est le créateur de la communauté Nuxtjs Africa et très passionné…
Plus à propos
Kelvin

Dans cette deuxième partie de la série Mirage JS Deep Dive, nous examinerons les usines, les montages et les sérialiseurs de Mirage JS. Nous verrons comment ils activent la simulation d’API rapide à l’aide de Mirage.

Dans l’article précédent de cette série, nous avons sous-étudié les modèles et les associations en ce qui concerne Mirage. J’ai expliqué que les modèles nous permettent de créer des données fictives dynamiques que Mirage pourrait servir à notre application lorsqu’elle fait une demande à nos points de terminaison fictifs. Dans cet article, nous examinerons trois autres fonctionnalités de Mirage qui permettent un mocking API encore plus rapide. Plongeons dedans!

Remarque: Je vous recommande fortement de lire mes deux premiers articles si vous ne souhaitez pas avoir une idée vraiment solide de ce qui serait discuté ici. Vous pouvez cependant toujours suivre et référencer les articles précédents si nécessaire.

Des usines

Dans un article précédent, j’ai expliqué comment Mirage JS est utilisé pour se moquer de l’API backend, supposons maintenant que nous nous moquons d’une ressource de produit dans Mirage. Pour y parvenir, nous créerions un gestionnaire d’itinéraire qui sera responsable de l’interception des demandes à un point d’extrémité particulier, et dans ce cas, le point d’extrémité est api/products. Le gestionnaire d’itinéraire que nous créons retournera tous les produits. Voici le code pour y parvenir dans Mirage:

import { Server, Model } from 'miragejs';

new Server({
    models: {
      product: Model,
    },

   routes() {
        this.namespace = "api";
        this.get('products', (schema, request) => {
        return schema.products.all()
    })
   }
});
    },

Le résultat de ce qui précède serait:

{
  "products": []
}

Nous voyons dans la sortie ci-dessus que la ressource produit est vide. Ceci est cependant attendu car nous n’avons pas encore créé d’enregistrements.

Conseil de pro: Mirage fournit le raccourci nécessaire pour les points de terminaison API classiques. Ainsi, le gestionnaire d’itinéraire ci-dessus pourrait également être aussi court que: this.get('/products').

Créons des enregistrements de product modèle à stocker dans la base de données Mirage à l’aide du seeds méthode sur notre Server exemple:

 seeds(server) {
      server.create('product', { name: 'Gemini Jacket' })
      server.create('product', { name: 'Hansel Jeans' })
  },

Le résultat:

{
  "products": [
    {
      "name": "Gemini Jacket",
      "id": "1"
    },
    {
      "name": "Hansel Jeans",
      "id": "2"
    }
  ]
}

Comme vous pouvez le voir ci-dessus, lorsque notre application frontale fait une demande /api/products, il récupérera une collection de produits telle que définie dans le seeds méthode.

En utilisant le seeds pour semer la base de données de Mirage est une étape de devoir créer manuellement chaque entrée comme un objet. Cependant, il ne serait pas pratique de créer 1000 (ou un million) de nouveaux enregistrements de produits en utilisant le modèle ci-dessus. D’où la nécessité de des usines.

Explication des usines

Les usines sont un moyen plus rapide de créer de nouveaux enregistrements de base de données. Ils nous permettent de créer rapidement plusieurs enregistrements d’un modèle particulier avec des variations à stocker dans la base de données Mirage JS.

Les usines sont également des objets qui facilitent la génération de données d’apparence réaliste sans avoir à semer ces données individuellement. Les usines sont plus recettes ou plans pour créer des enregistrements à partir de modèles.

Créer une usine

Examinons une usine en en créant une. L’usine que nous créerions sera utilisée comme modèle pour créer de nouveaux produits dans notre base de données Mirage JS.

import { Factory } from 'miragejs'

new Server({
    // including the model definition for a better understanding of what’s going on
    models: {
        product: Model
    },
    factories: {
        product: Factory.extend({})
    }
})

D’après ce qui précède, vous verriez que nous avons ajouté un factories propriété à notre Server instance et définir une autre propriété à l’intérieur qui par convention est du même nom que le modèle, nous voulons créer une usine pour, dans ce cas, ce modèle est le product modèle. L’extrait ci-dessus illustre le modèle que vous suivriez lors de la création d’usines dans Mirage JS.

Bien que nous ayons une usine pour product modèle, nous n’y avons vraiment pas ajouté de propriétés. Les propriétés d’une usine peuvent être des types simples comme cordes, booléens ou Nombres, ou les fonctions qui renvoient des données dynamiques comme nous le verrions dans la mise en œuvre complète de notre nouvelle usine de produits ci-dessous:

import { Server, Model, Factory } from 'miragejs'

new Server({
    models: {
        product: Model
    },

   factories: {
      product: Factory.extend({
        name(i) {
          //  i is the index of the record which will be auto incremented by Mirage JS
          return `Awesome Product ${i}`; // Awesome Product 1, Awesome Product 2, etc.
        },
        price() {
          let minPrice = 20;
          let maxPrice = 2000;
          let randomPrice =
            Math.floor(Math.random() * (maxPrice - minPrice + 1)) + minPrice;
          return `$ ${randomPrice}`;
        },
        category() {
          let categories = [
            'Electronics',
            'Computing',
            'Fashion',
            'Gaming',
            'Baby Products',
          ];
          let randomCategoryIndex = Math.floor(
            Math.random() * categories.length
          );
          let randomCategory = categories[randomCategoryIndex];
          return randomCategory;
        },
         rating() {
          let minRating = 0
          let maxRating = 5
          return Math.floor(Math.random() * (maxRating - minRating + 1)) + minRating;
        },
      }),
    },
})

Dans l’extrait de code ci-dessus, nous spécifions une logique javascript via Math.random pour créer des données dynamiques à chaque fois que l’usine est utilisée pour créer un nouvel enregistrement de produit. Cela montre la force et la flexibilité des usines.

Créons un produit en utilisant l’usine que nous avons définie ci-dessus. Pour ce faire, nous appelons server.create et passez le nom du modèle (product) sous forme de chaîne. Mirage créera ensuite un nouvel enregistrement d’un produit en utilisant l’usine de produits que nous avons définie. Le code dont vous avez besoin pour ce faire est le suivant:

new Server({
    seeds(server) {
        server.create("product")
    }
})

Conseil de pro: Tu peux courir console.log(server.db.dump()) pour voir les enregistrements dans la base de données de Mirage.

Un nouvel enregistrement similaire à celui ci-dessous a été créé et stocké dans la base de données Mirage.

{
  "products": [
    {
      "rating": 3,
      "category": "Computing",
      "price": "$739",
      "name": "Awesome Product 0",
      "id": "1"
    }
  ]
}

Surpasser les usines

Nous pouvons remplacer une ou plusieurs des valeurs fournies par une fabrique en les passant explicitement comme ceci:

server.create("product", {name: "Yet Another Product", rating: 5, category: "Fashion" })

L’enregistrement résultant serait similaire à:

{
  "products": [
    {
      "rating": 5,
      "category": "Fashion",
      "price": "$782",
      "name": "Yet Another Product",
      "id": "1"
    }
  ]
}

créer une liste

Avec une usine en place, nous pouvons utiliser une autre méthode sur l’objet serveur appelé createList. Cette méthode permet la création de plusieurs enregistrements d’un modèle particulier en transmettant le nom du modèle et le nombre d’enregistrements que vous souhaitez créer. Voici son utilisation:

server.createList("product", 10)

Ou

server.createList("product", 1000)

Comme vous le constaterez, le createList La méthode ci-dessus prend deux arguments: le nom du modèle sous forme de chaîne et un entier positif non nul représentant le nombre d’enregistrements à créer. Donc, à partir de ce qui précède, nous venons de créer 500 enregistrements de produits! Ce modèle est utile pour les tests d’interface utilisateur, comme vous le verrez dans un futur article de cette série.

Agencements

Dans les tests de logiciels, un appareil d’essai ou fixation est un état d’un ensemble ou d’une collection d’objets qui servent de référence pour l’exécution de tests. Le but principal d’un appareil est de s’assurer que l’environnement de test est bien connu afin de rendre les résultats reproductibles.

Mirage vous permet de créer des appareils et de les utiliser pour amorcer votre base de données avec les données initiales.

Remarque: Il est recommandé d’utiliser des usines 9 fois sur 10 car elles rendent vos mocks plus faciles à entretenir.

Créer un appareil

Créons un appareil simple pour charger des données dans notre base de données:

 fixtures: {
      products: [
        { id: 1, name: 'T-shirts' },
        { id: 2, name: 'Work Jeans' },
      ],
  },

Les données ci-dessus sont automatiquement chargées dans la base de données en tant que données initiales de Mirage. Cependant, si vous avez défini une fonction de semences, Mirage ignorerait votre appareil avec les hypothèses que vous vouliez qu’il soit remplacé et utiliserait plutôt des usines pour semer vos données.

Appareils en conjonction avec les usines

Mirage prend des dispositions pour que vous utilisiez les luminaires aux côtés des usines. Vous pouvez y parvenir en appelant server.loadFixtures(). Par exemple:

 fixtures: {
    products: [
      { id: 1, name: "iPhone 7" },
      { id: 2, name: "Smart TV" },
      { id: 3, name: "Pressing Iron" },
    ],
  },

  seeds(server) {
    // Permits both fixtures and factories to live side by side
    server.loadFixtures()

    server.create("product")
  },

Fichiers de luminaires

Idéalement, vous voudriez créer vos appareils dans un fichier séparé de server.js et l’importer. Par exemple, vous pouvez créer un répertoire appelé fixtures et créer products.js. Dans products.js ajouter:

// /fixtures/products.js
export default [
  { id: 1, name: 'iPhone 7' },
  { id: 2, name: 'Smart TV' },
  { id: 3, name: 'Pressing Iron' },
];

Puis dans server.js importer et utiliser le produit comme ceci:

import products from './fixtures/products';
 fixtures: {
    products,
 },

J’utilise un raccourci de propriété ES6 afin d’affecter le tableau de produits importé au products propriété de l’objet fixtures.

Il convient de mentionner que les luminaires seront ignorés par Mirage JS pendant les tests, sauf que vous le lui dites explicitement en utilisant server.loadFixtures()

Usines vs luminaires

À mon avis, vous devez vous abstenir d’utiliser des luminaires, sauf si vous avez un cas d’utilisation particulier où ils sont plus adaptés que les usines. Les appareils ont tendance à être plus verbeux tandis que les usines sont plus rapides et impliquent moins de frappes.

Sérialiseurs

Il est important de renvoyer une charge utile JSON qui est attendue à l’interface donc sérialiseurs.

Un sérialiseur est un objet chargé de transformer un ** modèle ** ou ** collection ** renvoyé par vos gestionnaires de routes en une charge utile JSON formatée comme l’attend votre application frontale.

Mirage Docs

Prenons par exemple ce gestionnaire d’itinéraire:

this.get('products/:id', (schema, request) => {
        return schema.products.find(request.params.id);
      });

Un sérialiseur est responsable de la transformation de la réponse à quelque chose comme ceci:

{
  "product": {
    "rating": 0,
    "category": "Baby Products",
    "price": "$654",
    "name": "Awesome Product 1",
    "id": "2"
  }
}

Sérialiseurs intégrés Mirage JS

Pour travailler avec les sérialiseurs Mirage JS, vous devez choisir le sérialiseur intégré par lequel commencer. Cette décision serait influencée par le type de JSON que votre backend enverrait éventuellement à votre application frontale. Mirage est fourni avec les sérialiseurs suivants:

  • JSONAPISerializer
    Ce sérialiseur suit le JSON: spécification API.
  • ActiveModelSerializer
    Ce sérialiseur est destiné à imiter les API qui ressemblent aux API Rails construites avec le gemme active_model_serializer.
  • RestSerializer
    le RestSerializer est le sérialiseur «catch all» de Mirage JS pour les autres API courantes.

Définition du sérialiseur

Pour définir une sérialisation, importez le sérialiseur approprié, par exemple RestSerializer de miragejs ainsi:

import { Server, RestSerializer } from "miragejs"

Puis dans le Server exemple:

new Server({
  serializers: {
    application: RestSerializer,
  },
})

le RestSerializer est utilisé par Mirage JS par défaut. Il est donc redondant de le définir explicitement. L’extrait ci-dessus est à titre d’exemple.

Voyons la sortie des deux JSONAPISerializer et ActiveModelSerializer sur le même gestionnaire d’itinéraire que nous avons défini ci-dessus

JSONAPISerializer

import { Server, JSONAPISerializer } from "miragejs"
new Server({
  serializers: {
    application: JSONAPISerializer,
  },
})

Le résultat:

{
  "data": {
    "type": "products",
    "id": "2",
    "attributes": {
      "rating": 3,
      "category": "Electronics",
      "price": "$1711",
      "name": "Awesome Product 1"
    }
  }
}

ActiveModelSerializer

Pour voir ActiveModelSerializer au travail, je voudrais modifier la déclaration de category dans l’usine de produits pour:

productCategory() {
          let categories = [
            'Electronics',
            'Computing',
            'Fashion',
            'Gaming',
            'Baby Products',
          ];
          let randomCategoryIndex = Math.floor(
            Math.random() * categories.length
          );
          let randomCategory = categories[randomCategoryIndex];
          return randomCategory;
        },

Tout ce que j’ai fait, c’est changer le nom de la propriété en productCategory pour montrer comment le sérialiseur le gérerait.

Ensuite, nous définissons le ActiveModelSerializer sérialiseur comme ça:

import { Server, ActiveModelSerializer } from "miragejs"
new Server({
  serializers: {
    application: ActiveModelSerializer,
  },
})

Le sérialiseur transforme le JSON renvoyé en:

{
  "rating": 2,
  "product_category": "Computing",
  "price": "$64",
  "name": "Awesome Product 4",
  "id": "5"
}

Vous remarquerez que productCategory a été transformé en product_category qui est conforme à la gemme active_model_serializer de l’écosystème Ruby.

Personnalisation des sérialiseurs

Mirage offre la possibilité de personnaliser un sérialiseur. Supposons que votre application nécessite que vos noms d’attribut soient camelcas, vous pouvez remplacer RestSerializer pour y parvenir. Nous utiliserions le lodash bibliothèque d’utilitaires:

import { RestSerializer } from 'miragejs';
import { camelCase, upperFirst } from 'lodash';
serializers: {
      application: RestSerializer.extend({
        keyForAttribute(attr) {
          return upperFirst(camelCase(attr));
        },
      }),
    },

Cela devrait produire du JSON de la forme:

 {
      "Rating": 5,
      "ProductCategory": "Fashion",
      "Price": "$1386",
      "Name": "Awesome Product 4",
      "Id": "5"
    }

Emballer

Tu l’as fait! J’espère que vous avez une meilleure compréhension de Mirage via cet article et que vous avez également vu comment l’utilisation d’usines, de montages et de sérialiseurs vous permettrait de créer des modèles d’API de type production avec Mirage. Recherchez la prochaine partie de cette série.

Smashing Editorial(rail)

Auteur de l’article : manuboss