1.8.22 • Published 24 hours ago

@duplojs/duplojs v1.8.22

Weekly downloads
-
License
ISC
Repository
github
Last release
24 hours ago

DuploJS

NPM version

DuploJS est un framework TypeScript (Type-safe) back-end orienté fonctionnel simple a prendre en main qui pourrait même être utilisé par des développeurs front-end ;).

Duplojs est conçu pour les développeurs qui accordent de l'importance à la clarté. Le framework a été pensé pour rendre toutes les opérations de vérification d'une route explicites, sans pour autant être trop "verbeux". Duplojs encourage la segmentation et la flexibilité afin que vos routes ne soient plus qu'un assemblage de briques. Chaque route deviendra une belle monade qui vous racontera une histoire sans erreurs et où chaque personnage joue correctement et successivement son rôle.

Sommaire

Instalation

Initialiser un projet vierge

npm create duplojs

Installation basique

npm i @duplojs/duplojs

Premier pas

Initialiser le serveur

import Duplo, {zod} from "@duplojs/duplojs"; // Duplojs intègre zod directement

const duplo = Duplo({port: 1506, host: "localhost", environment: "DEV"});

// Définition des routes...

duplo.launch();

Déclarer une route

duplo
.declareRoute("GET", "/user/{id}")
.handler((floor, response) => {
    response.code(200).info("quoicoubeh").send();
});

Comme vous pouvez le voir, vous n'avez pas un accès direct à la requête, et TANT MIEUX, car tel que je vous connais (bande de sagouins), vous auriez fait ça n'importe comment.

Comment accéder aux valeurs de la request

duplo
.declareRoute("GET", "/user/{id}")
.extract({
    params: {
        id: zod.coerce.number()
    },
    headers: {
        role: zod.string().min(2).max(15)
    }
})
.handler((floor, response) => {
    response.code(200).info("quoicoubeh").send();
});

Grâce à la fonction extract, vous pouvez, à l'aide de zod, extraire ce que vous souhaitez de la requête et garantir le type des variables :

  • Le paramètre "id" n'acceptera qu'un nombre ou une chaîne de caractères contenant un nombre.
  • Le champ "role" des headers n'acceptera qu'une chaîne de caractères ayant entre 2 et 15 caractères.

Comment accéder aux valeurs

duplo
.declareRoute("GET", "/user/{id}")
.extract({
    params: {
        id: zod.coerce.number()
    },
    headers: {
        role: zod.string().min(2).max(15)
    }
})
.handler((floor, response) => {
    response.code(200).info("quoicoubeh").send({
        id: floor.pickup("id"),
        role: floor.pickup("role")
    });
});

L'objet "floor" représente le sol de votre chambre. Tout comme les gros nerds que nous sommes, quand on a besoin de ranger quelque chose, on le jette par terre floor.drop("caleçons", "sale"), puis on les ramasse plus tard avec floor.pickup("caleçons") (c'est juste un Map qui se balade à travers toutes les fonctions d'une route). Toutes les valeurs vérifiées dans l'extract sont automatiquement "drop" sur votre sol.

Comment faire plus de vérifications

Vous êtes peut-être tentés de faire toutes les vérifications dans le handler mais il faut que vous gardiez une chose en tête ! Le handler correspond à l'action finale, une fois arrivé ici en théorie il n'y a plus aucune vérification à faire.

Mais comment faire alors ? Simplement grâce au checker:

const userExist = duplo
.createChecker("userExist") // le nom du checker
// valeur par défaut des options
.options({ 
    index: "id" as "id" | "firstname" 
})
.handler((input: number | string, output, options) => {
    const user = await myDataBase.user.findOne({
        [options.index]: input
    });

    if(!user) {
        return output("user.notexist", null);
    }
    else {
        return output("user.exist", user);
    }
})
// fonction non obligatoire
.preCompletion( 
    "wantUser",
    {
        result: "user.exist",
        catch: (response, info) => response.code(404).info(info).send(),
        indexing: "user",
    }
)
.build();

Un checker est une fonction qui prend en entrée une valeur et doit toujours renvoyer une information et une donnée. Son implémentation permet d'effectuer une vérification. Dans l'exemple ci-dessus, le checker indique prendre en entrée un nombre ou une chaîne de caractères. Il propose une option "index" qui dans notre cas permet de définir par quelle clé on cherche un utilisateur. On a aussi ajouté une précomplétion qui simplifie l'implémentation du checker.

Implémenter un checker

duplo
.declareRoute("GET", "/user/{id}")
.extract({
    params: {
        id: zod.coerce.number()
    },
    headers: {
        role: zod.string().min(2).max(15)
    }
})
.check(
    userExist,
    {
        input: (pickup) => pickup("id"), // valeur d'entrée
        result: "user.exist", // info attendue pour continuer
        catch: (response, info) => response.code(404).info(info).send(), // action effectuée si l'info n'est pas celle attendue
        indexing: "user", // index de drop du resultat
        options: {index: "id"} // option utilisée
    }
)
// ou
.check(
    userExist,
    {
        input: (pickup) => pickup("id"),
        ...userExist.preCompletions.wantUser, // utilisation de la précomplétion
        options: {index: "id"}
    }
)
.handler((floor, response) => {
    response.code(200).info("quoicoubeh").send(floor.pickup("user"));
});

Ici, le checker prend comme valeur d'entrée l'ID qui a été précédemment "drop" au sol lors de l'extraction. Ensuite, il vérifie si la valeur de sortie est égale à "user.exist". Si c'est le cas, il continue l'exécution et indexe les données de sortie à "user". Sinon, il lance la fonction "catch" qui va renvoyer une erreur 404.

Utiliser un cut

duplo
.declareRoute("GET", "/user/{id}")
.extract({
    params: {
        id: zod.coerce.number()
    },
    headers: {
        role: zod.string().min(2).max(15)
    }
})
.cut((floor, response) => {
    if(floor.pickup("role") !== "admin")response.code(403).info("forbidden").send()
})
.check(
    userExist,
    {
        input: (pickup) => pickup("id"),
        ...userExist.preCompletions.wantUser, // utilisation de la précomplétion
        options: {index: "id"}
    }
)
.handler((floor, response) => {
    response.code(200).info("quoicoubeh").send(floor.pickup("user"));
});

Les checkers sont conçus pour être utilisés à plusieurs endroits, mais il peut arriver de devoir effectuer une opération très spécifique. C'est pour celà que les cuts ont été créés.

⚠️ Attention à ne pas abuser des cuts, sinon vous vous éloignerez de l'utilité première, qui est la construction de code à base de briques réutilisables. ⚠️

Respecter l'exécution linéaire

Pour que Duplojs fonctionne correctement, il faut respecter son exécution. Une request a un chemin synchronisé et des étapes à franchir. Si vous souhaitez utiliser une réponse après une promesse, il vous faudra toujours utiliser await pour que l'exécution se fasse de manière linéaire.

duplo
.declareRoute("GET", "/user/{id}")
// hook, extract, process, checker, cut...
.handler(async (floor, response) => {

    // ✖ ne fonctionne pas (ti é con ou koi ?)
    // celà provoquera une erreur qui indiquera que rien n'a été envoyé
    new Promise(resolve => setTimeout(resolve, 1000))
    .then(() => response.code(200).info("j'effectue le dab").send());

    // ✔ fonctionne correctement (y comprend vite mais y faut lui expliquer longtemps)
    // l'exécution est linéaire donc celà ne pose aucun problème
    await new Promise(resolve => setTimeout(resolve, 1000));
    response.code(200).info("il est mort pioupiou").send();
});

Répondre est une erreur

Quand les fonctions send, sendFile, redirect et download sont appelées, elles créent une exception qui permet de stopper court au processus pour enchaîner sur le reste du cycle de vie de la request. Cependant, celà peut poser problème si vous appelez l'une de ces fonctions dans un try catch.

duplo
.declareRoute("GET", "/user/{id}")
// hook, extract, process, checker, cut...
.handler((floor, response) => {
    try{
        response.code(200).info("bien se passé").send();

        throw "bebou";
    }
    catch(error){
        // error === response;

        if(error instanceof Response) throw error;
    }
});

Retour vers le Sommaire.

1.8.22

24 hours ago

1.8.21

3 days ago

1.8.20

18 days ago

1.8.18

18 days ago

1.8.19

18 days ago

1.6.16

27 days ago

1.5.16

29 days ago

1.4.15

1 month ago

1.4.14

1 month ago

1.3.14

1 month ago

1.2.14

2 months ago

1.2.13

2 months ago

1.2.12

2 months ago

1.1.12

2 months ago

1.1.11

2 months ago

1.1.9

3 months ago

1.1.10

3 months ago

1.1.8

3 months ago

1.1.7

3 months ago

1.1.6

3 months ago

1.1.5

3 months ago

1.1.4

3 months ago

1.1.3

3 months ago

1.1.2

3 months ago

0.13.28

5 months ago

0.13.27

5 months ago

0.13.23

6 months ago

0.13.22

6 months ago

0.13.20

6 months ago

0.13.19

6 months ago

0.12.19

6 months ago

0.12.17

7 months ago

0.8.16

7 months ago

0.8.15

8 months ago

0.8.14

8 months ago

0.7.14

8 months ago

0.6.14

8 months ago

0.6.13

8 months ago

0.6.12

8 months ago

0.6.11

8 months ago

0.6.10

8 months ago

0.6.9

8 months ago

0.6.8

8 months ago

0.6.7

8 months ago

0.6.6

8 months ago

0.5.6

8 months ago

0.4.6

8 months ago

0.4.5

8 months ago

0.0.0

8 months ago

0.4.4

8 months ago

0.4.3

8 months ago

0.4.2

9 months ago

0.0.1

9 months ago