Node.js

Node.js

Mongoose, les promises et Q

Mongoose, les promises et Q

Q est un module de promises pour Node.js qui implémente le standard Promises/A+. Il est devenu peu à peu l’implémentation de référence, et de nombreux tutoriaux en présentent différentes fonctionnalités.

De même, Mongoose est le module de facto à utiliser lorsqu’on intègre la base MongoDB dans un projet Node.js, puisqu’il est supporté officiellement par MongoDB, Inc.

Depuis quelques temps maintenant, le module Mongoose propose le support des promises en plus de son fonctionnement via callback via l’appel de la fonction exec. C’est à dire, qu’il est possible d’écrire:

Conference.findOne({ id: 12 }).exec()
.then (conference) ->
    console.log conference
    next()
, (err) ->
    # handle error here.

Malheureusement, l’implémentation des promises utilisées par Mongoose n’est pas compatible avec l’implémentation Q. Notamment, il n’est pas possible d’utiliser la fonction fail, et d’écrire le code précédent de la façon suivante:

Conference.findOne({ id: 12 }).exec()
.then (conference) ->
    console.log conference
    next()
.fail (err) ->
    # handle error here.

La promise renvoyée par Mongoose n’est donc pas directement intégrable avec les promises Q. On peut donc penser qu’il est compliqué d’intégrer les deux types de promises.

Heureusement Q propose une solution simple pour les intégrer avec la fonction Q() qui permet de wrapper une promise Mongoose dans une promise Q, et donc d’intégrer les promises Mongoose dans des chaînages de promises Q, ou bien d’utiliser tout simplement les syntaxes Q.

Ainsi, vous devrez écrire le code suivant:

Q(Conference.findOne({ id: 12 }).exec())
.then (conference) ->
    console.log conference
    next()
.fail (err) ->
    # handle error here.

De façon plus globale, si vous travaillez avec une autre librairie de promises que Q, vous pouvez wrapper vos promises avec la fonction Q() dans la mesure où votre librairie propose une syntaxe compatible avec les wrappers Q. Dixit la doc de la librairie:

Q can exchange promises with jQuery, Dojo, When.js, WinJS, and more

Pour aller plus loin

La homepage GitHub de la librairie Q et sa documentation:

https://github.com/kriskowal/q

Logger le contenu de vos objets avec Node.js

Logger le contenu de vos objets avec Node.js

Le contenu des logs est un élément essentiel de votre programme, bien souvent laissé de côté, il peut s’avérer précieux en cas problème.

En particulier, il arrive de vouloir logger le contenu d’un objet ou bien une de ses propriétés. Bien souvent, le premier réflexe sera d’en afficher le contenu en concaténant son contenu dans une chaine de caractère comme suit:

foobar = foo: "bar"
console.log "Contenu de la variable foobar: '#{foobar}'"

Malheureusement, le résultat ne correspond pas toujours à ce qu’on imagine:

Contenu de la variable foobar: '[object Object]'

Vu comme ça, on n’en fera pas grand chose si on met le nez dans les logs. Bien sûr, il est possible d’afficher la valeur de la propriété ‘foobar’ de l’objet:

console.log "Contenu de la variable foobar: '#{foobar.foo}'"

Le résultat sera un peu meilleur car on sera en mesure de logger la valeur de foo:

Contenu de la variable foobar: 'bar'

Dans notre cas, nous avons de la chance, car la variable ‘foo’ est de type String. Mais si la variable en question est un objet ou bien un tableau, nous tomberons sur le même problème.

JavaScript et Node.js nous proposent au moins deux solutions pour nous aider à produire un log convenable: La fonction ‘JSON.stringify’, et la fonction ‘inspect’ du module ‘util’.

JSON.stringify()

Bien connu dans le mode du JavaScript côté browser pour sérialiser le contenu d’une requête AJAX par exemple, on ne pense pas toujours à utiliser cette méthode pour sérialiser un objet ou bien un tableau JavaScript dans le but d’en logger son contenu:

console.log "Contenu de la variable foobar: '#{JSON.stringify(foobar})'"

On obtient déjà quelque chose de bien plus intéressant, c’est à dire un log avec un descriptif complet de l’objet au format JSON:

Contenu de la variable foobar: '{"foo":"bar"}'

Des objets plus complexes peuvent néanmoins devenir difficile à relire dans les logs, il ne faut donc pas hésiter à renseigner les informations de formatage du JSON lors de l’appel de la méthode ‘stringify’, qui permettent d’obtenir un log plus lisible avec un contenu bien indenté:

console.log "Contenu de la variable foobar: '#{JSON.stringify(foobar, undefined, 2})'"

ce qui donne:

Contenu de la variable foobar: '{
  "foo": "bar"
}'

Le dernier paramètre permet de spécifier l’indentation souhaitée.

La documentation complète de la méthode stringify peut être consulté sur le site de Mozilla: https://developer.mozilla.org/fr/docs/JavaScript/Reference/Objets_globaux/JSON/stringify

La méthode JSON.stringify peut être utilisée également avec des tableaux:

foo = [ "foo", "bar" ]
console.log "Contenu de la variable foobar: '#{JSON.stringify(foo, undefined, 2)}'"

ce qui donne:

Contenu de la variable foobar: '[
  "foo",
  "bar"
]'

Malheureusement, cela ne fonctionne pas avec les fonctions qui ne font pas partie du standard JSON:

bar = (foo, bar) -> "#{foo}-#{bar}"
console.log "Contenu de la variable foobar: '#{JSON.stringify(bar, undefined, 2)}'"

ce qui donne:

Contenu de la variable foobar: 'undefined'

Il ne faut pas oublier que nous détournons une fonctionnalité qui n’est pas spécialement faite pour le log au départ… Heureusement notre bonne vieille méthode toString() appelée sur la fonction nous sortira d’affaire:

console.log "Contenu de la variable foobar: '#{bar.toString()}'"

ou tout simplement:

console.log "Contenu de la variable foobar: '#{bar}'"

donne:

Contenu de la variable foobar: 'function (foo, bar) {
    return "" + foo + "-" + bar;
  }

util.inspect()

Le module util de Node.js fournit quelques fonctions intéressantes, dont la fonction: inspect. Elle permet de formatter un contenu de la façon que le réalise la fonction JSON.stringify que ce soit un objet ou bien un tableau. Elle a l’avantage d’être plus souple en proposant différentes options de sérialisation telles qu’une profondeur limite d’inspection ou bien encore la capacité d’appeler la méthode inspect() sur les sous-objets de l’arbre, lorsqu’ils la propose, afin de produire un contenu sérialisé spécifique.

Par exemple, les appels suivants:

util = require 'util'

console.log "Contenu de la variable foobar: '#{util.inspect(foobar)}'"
console.log "Contenu de la variable foobar: '#{util.inspect(foo)}'"
console.log "Contenu de la variable foobar: '#{util.inspect(bar)}'"

donneront:

Contenu de la variable foobar: '{ foo: 'bar' }'
Contenu de la variable foobar: '[ 'foo', 'bar' ]'
Contenu de la variable foobar: '[Function]'

Et la customisation de la sérialisation comme suit:

qix = { foo:"bar", foobar: { inspect: () -> "Some custom representation of foobar" } }
console.log "Contenu de la variable foobar: '#{util.inspect(qix)}'"

donnera:

Contenu de la variable foobar: '{ foo: 'bar', foobar: Some custom representation of foobar }'

On notera avec ce dernier exemple que la fonction util.inspect() n’a pas vocation à produire un JSON valide, mais elle produira par défaut une notation proche du JSON.

Il est possible entre autre d’afficher les propriétés non-enumerables d’un objet, de coloriser le résultat de l’appel ou bien encore de désactiver l’appel des inspections customisées sur les objets.

Pour approfondir: http://nodejs.org/api/util.html#util_util_inspect_object_options

Pour aller plus loin …

Sachez qu’il existe des modules Node.js dédiés à la sérialisation d’objets à des fins d’analyse. Par exemple, le module nodedump permet de logger dans une sortie HTML un tableau qui détaille le contenu de l’objet:

nodedump

Bien entendu, vous pourrez toujours préférer le debugger de votre IDE favori, son côté interactif apporte de nombreux bénéfices, et l’évaluation d’expressions se révèle être d’une grande aide:

debugger