npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@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.git

Usage

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.automatedTimestamps

ou 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");
   }