@wizim-dev/crud-server
v0.0.1
Published
Helper to create automatic CRUD routes
Readme
#Snark CRUD Server Ce module permet de créer automatiquement les routes de CRUD reliées à MongoDB (pour l'instant). Ce module marche "out of the box" avec le snark-backoffice.
Installation
npm install git+ssh://[email protected]:snarkfactory/snark-crud-server.gitUsage
const CRUD = require('snark-crud-server');
let api = express.Router();
CRUD(api, {configuration...});
Configuration
Il n'y a aucune obligation de mettre une configuration pour les collections. Seule la configuration de la base de données est obligatoire.
{
// configuration des accès à la base MongoDB
database: {
host: "",
port: "",
name: "",
user: "",
password: ""
},
// Logger (optionnel)
logger: ...,
// Securité (optionnel)
isAuthentified: (token: string) => Promise<boolean>,
// pour chaque collection (optionnel), les fonctions sont toutes optionnelles.
collectionName: {
completeList: function(items, options) {
// appelée après avoir chargé les éléments en mode LIST.
// options correspond à la partie des options de la collection.
return Promise.resolve(items);
},
completeSingle: function(item, options) {
// appelée après avoir chargé l'élément en mode READ.
// options correspond à la partie des options de la collection.
return Promise.resolve(item);
}
transformer: function(data, options, metadata, oldItem) {
// transforme les données reçues d'un objet avant qu'elles soient envoyées à la fonction d'UPDATE et de CREATE
// - data contient les données à transformer éventuellement
// - options correspond à la partie des options de la collection.
// - metadata est un objet vide qui peut être rempli et qui sera ensuite passé au callback **afterCreate**
// - oldItems est l'objet récupéré de la base de données lors d'un UPDATE (il est undefined pour un CREATE).
return Promise.resolve(data);
},
afterCreate: function(item, options, metadata) {
// callback appelé après une création.
// - item est l'objet inséré,
// - options correspond à la partie des options de la collection.
// - metadata est un objet qui a pu être rempli par le callback transformer au besoin.
},
afterUpdate: function(item, options) {
// callback appelé après une modification.
// - item est l'objet modifié,
// - options correspond à la partie des options de la collection.
// la fonction doit retourner une promesse (mais la valeur n'est pas utilisée)
return Promise.resolve()
},
beforeDelete: function(item, options) {
// callback appelé avant une suppression.
// - item est l'objet à supprimer,
// - options correspond à la partie des options de la collection.
// La fonction doit retourner null si la suppression est acceptée
// et une erreur (string) sinon pour indiquer l'erreur qui sera remontée au front.
return Promise.resolve(null);
}
afterDelete: function(id, options) {
// callback appelé après une suppression.
// - id est l'identifiant de l'objet supprimé,
// - options correspond à la partie des options de la collection.
// la fonction doit retourner une promesse (mais la valeur n'est pas utilisée)
},
},
...
}Routes et réponses
Toutes les routes produisent le même type d'erreur :
{success: false, error: err}GET /crud/list/:collection
{success: true, collection: collection, items: items}Paramètres de requête possibles :
- skip: (int) offset de récupération de données.
- limit: (int) nombre d'éléments maximums renvoyés.
- sort: tri du résultat. Format: liste de propriétés séparées par des virgules. si "-" devant la propriété, cette propriété est classée dans l'ordre décroissant.
POST /crud/create/:collection
{success: true, collection: collection, item: item}GET /crud/read/:collection/:id
{success: true, collection: collection, item: item}PUT /crud/update/:collection/:id
{success: true, collection: collection, item: item}DELETE /crud/delete/:collection/:id
{success: true, collection: collection}GET /crud/count/:collection
{success: true, collection: collection, filter: filter, count: count}Paramètres de requête possibles :
- filter: (json) Filtre passé directement à la requête de comptage.
// TODO: on ne doit pas passer directement le filtre à la requête, cela pourrait entraîner des injections d'erreurs de sécurité.
Validation
Il est possible de retourner une erreur sur le transformer: il suffit de reject("error in string") pour voir apparaitre la string dans le backoffice et donc induire en erreur le formulaire.
collectionName: {
transformer: () => {
return new Promise((resolve, reject) => {
const badData = true;
if (badData) {
reject("Champs obligatoire ....");
}
});
}
},Sécurité
Pour activer un middleware de sécurité sur toutes les routes, il suffit de spécifier l'option isAuthentified. Cette fonction prend un token et doit retourner une promesse avec la valeur true si le token représente un utilisateur authentifié ou false sinon.
Si l'option n'est pas présente, le middleware de sécurité laisse tout passer.
Fonctions
CRUD.saveImageFile
Cette fonction permet de sauvegarder un fichier envoyé en base64 data:image dans une propriété (pour le CREATE et l'UPDATE).
CRUD.saveImageFile(data, propertyName, imageDir, imageNameTarget, imageExtensionTarget)Paramètres obligatoires
- data: objet créé ou mis à jour
- propertyName: nom de la propriété qui peut contenir l'image en base64 commençant par data:image ( string | string[] )
- imageDir: chemin du répéertoire de destination de l'image.
Paramètres optionnels
- imageNameTarget: nom de l'image souhaitée à la fin (sinon, le nom est généré par un UUID);
- imageExtensionTarget: nom de l'extension désirée (sinon, elle est déduite du mime/type contenu dans les données).
Typiquement elle est utilisée dans une des fonction transformer. Par exemple :
- Avec propertyName de type string:
transformer: function(data, options) {
return CRUD.saveImageFile(data, "imageField", "/path/to/image");
}
// accessing data["imageField"]- Avec propertyName de type array:
transformer: function(data, options) {
return CRUD.saveImageFile(data, ["attribut1", "attribut2"], "/path/to/image");
}
// accessing data["attribut1"]["attribut2"]CRUD.saveFile
Cette fonction permet de sauvegarder un fichier envoyé en base64 data:mimetype dans une propriété (pour le CREATE et l'UPDATE).
CRUD.saveFile(data, propertyName, fileDir, fileeNameTarget, fileExtensionTarget)Paramètres obligatoires
- data: objet créé ou mis à jour
- propertyName: nom de la propriété qui peut contenir lefichier en base64 ( string | string[] )
- fileDir: chemin du répéertoire de destination de le fichier.
Paramètres optionnels
- fileNameTarget: nom du fichier souhaité à la fin (sinon, le nom est généré par un UUID);
- fileExtensionTarget: nom de l'extension désirée (sinon, elle est déduite du mime/type contenu dans les données).
Typiquement elle est utilisée dans une des fonction transformer. Par exemple :
- Avec propertyName de type string:
transformer: function(data, options) {
return CRUD.saveFile(data, "fileField", "/path/to/file");
}
// accessing data["fileField"]- Avec propertyName de type Array:
transformer: function(data, options) {
return CRUD.saveFile(data, ["attribut1", "attribut2"],/path/to/file");
}
// accessing data["attribut1"]["attribut2"]CRUD.encryptPassword
Cette fonction permet d'encrypter (en BCrypt) un mot de passe dans les données reçues.
CRUD.encryptPassword(data, propertyPassword, propertyNewPassword, saltRoundsCount)Paramètres obligatoires
- data: objet créé ou mis à jour
- propertyPassword: nom de la propriété qui contient le mot de passe.
Paramètres optionnels
- propertyNewPassword: nom de la propriété qui contient le nouveau mot de passe à encrypter. Si cette propriété est absente, on suppose que le mot de passe est en clair dans propertyPassword et on écrasera cette valeur avec le mot de passe encrypter.
- saltRoundsCount: Nombre de "tour de salage" de la clé (par défaut, 10)
Typiquement elle est utilisée dans une des fonction transformer. Par exemple :
transformer: function(data, options, metadata, oldItem) {
return CRUD.encryptPassword(data, "password", "newPassword");
}CRUD.comparePassword
Cette fonction permet de comparer un mot de passe en clair avec un mot de passe encrypté.
CRUD.comparePassword(password, data, propertyPassword)Paramètres obligatoires
- password: Mot de passe en clair à comparer
- data: objet contenant le mot de passe
- propertyPassword: nom de la propriété qui contient le mot de passe.
Typiquement elle est utilisée dans un handler d'authentification.
CRUD.createBOUser
Cette fonction permet de créer facilement un utilisateur du backoffice (table bouser) si celui-ci est un snark-backoffice.
CRUD.createBOUser = function(options, username, password)Paramètres obligatoiers
- options: Options est le même objet que celui passé lors de l'utilisation de la fonction CRUD. Le seul besoin est la propriété database qui doit contenir les accès à la base de données.
Paramètres optionnels
- username: nom de l'utilisateur du backoffice (par défaut "backoffice").
- password: mot de passe de l'utilisateur (par défaut "backoffice").
CRUD.automatedTimestamps
Cette fonction permet d'ajouter et mettre à jour automatiquement les champs createdAt et updatedAt dans les objets.
Elle peut être utilisée directement en middleware de la section transformer d'une configuration :
transformer: CRUD.automatedTimestampsou bien si on a d'autres choses à faire dans le transformer :
transformer: function(data, options, metadata, oldItem) {
return CRUD.automatedTimestamps(data)
.then(data => {
// ... do what you have to !
return Promise.resolve(data);
});
}Paramètres obligatoires
- data: objet créé ou mis à jour
- propertyPassword: nom de la propriété qui contient le mot de passe.
Paramètres optionnels
- propertyNewPassword: nom de la propriété qui contient le nouveau mot de passe à encrypter. Si cette propriété est absente, on suppose que le mot de passe est en clair dans propertyPassword et on écrasera cette valeur avec le mot de passe encrypter.
- saltRoundsCount: Nombre de "tour de salage" de la clé (par défaut, 10)
Typiquement elle est utilisée dans une des fonction transformer. Par exemple :
transformer: function(data, options) {
return CRUD.encryptPassword(data, "password", "newPassword");
}