Filtered Redis log of executed commands

If you deal with some kind of database, you should know by now that Redis is TEH AWESOME.

As part of the provided tools, the redis-cli binary is an invaluable tool to connect to a Redis database, via a TCP port or a UNIX socket (my preferred way).

Once connected to a Redis server via redis-cli you can send the MONITOR command. The clients then stops listening to regular inputs and starts to log every command received by the server, with a timestamp (seconds and microseconds).

Here is an output sample :

1353711173.069255 "MONITOR"
1353711204.631496 "SET" "users:1:login" "alfred"
1353711224.119123 "SET" "users:2:login" "tom"
1353711281.926336 "SADD" "users" "1" "2"
1353711297.878012 "SMEMBERS" "users"

The problem is that there doesn’t seem to be a built-in way to filter or save the command logs.

Redis being a good UNIX citizen acts like any other command regarding to input, outputs and pipes.

Let’s assume that the server is reachable on the default TCP port,

To simply print a command log
echo "MONITOR" | redis-cli
To print a filtered command log (only "add to Sets")
echo "MONITOR" | redis-cli | grep -i 'SADD'
To save a command log to a file
echo "MONITOR" | redis-cli > redis.log
To save a filtered command log to a file
echo "MONITOR" | redis-cli | grep -i 'SADD' > redis.log

NB : Redis is case insensitive for the commands it accepts.

Publié dans Informatique | Tagué , | Poster un commentaire

Multiple Redis instances on Mac OS X with Homebrew

I’ve already written (in french) about the benefit of having multiple Redis instances, and we use this technique on our servers.

On our development setup we use Mac OS X or Linux with Redis installed by a package manager. I’ll focus here on the Mac OS X + Homebrew part, but everything will be easy to adjust to a different OS or package manager.

Why do we need multiple Redis instances?

Every so often, we need or want to replace our local databases with the data from our production environment. We use a handful of different datastores : MySQL, Redis, MongoDB and Solr.

For MySQL, MongoDB and Solr, it’s quite trivial. We download dumps from our backup server and inject them into our development environment.
For Redis, it has never been that easy, here is why and what we’ve done to eliminate the pain.

How Redis stores it’s data

For each instance of a Redis server there is a dump file, usualy called dump.rdb that contains all the data needed by Redis. If you want to backup your Redis data, you just have to copy this file into another location. You don’t even need to stop the server since this file is always consistent. It may lack some data not yet written to disk (the delay depends on the configuratyion, usually a few seconds), but it is safe.

Since we’ve been using Redis, we wanted to separate different data parts from each other, with something more secure than a basic namespace in the keys. We’ve been using different “databases” inside a single Redis instance (there are 16 available by default), but everything is stored in a single dump.rdb file. As of Redis v2.4 I’ve not found a way to dump/restore only a specific database.

As I’ve said, we have 4 different dump files from our servers and only 1 (with 4 internal DBs) on our development environment which makes it impossible to import our production data locally.

The solution is quite simple ; let’s have as many Redis instances locally as on our production server.

Run multiple Redis instances locally

On Mac OS X, you can use Homebrew to manage third-parties packages, including Redis. When you install it, you get a binary (redis-server), a config file and a Launchd file. By default Homebrew doesn’t set Redis to start automaticaly but tells you what to do if you want this behavior.

$ brew info redis
redis 2.4.14

http://redis.io/

/usr/local/Cellar/redis/2.4.13 (9 files, 436K) *

https://github.com/mxcl/homebrew/commits/master/Library/Formula/redis.rb

==> Caveats
If this is your first install, automatically load on login with:
    mkdir -p ~/Library/LaunchAgents
    cp /usr/local/Cellar/redis/2.4.14/homebrew.mxcl.redis.plist ~/Library/LaunchAgents/
    launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.redis.plist

If this is an upgrade and you already have the homebrew.mxcl.redis.plist loaded:
    launchctl unload -w ~/Library/LaunchAgents/homebrew.mxcl.redis.plist
    cp /usr/local/Cellar/redis/2.4.14/homebrew.mxcl.redis.plist ~/Library/LaunchAgents/
    launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.redis.plist

To start redis manually:
    redis-server /usr/local/etc/redis.conf

To access the server:
    redis-cli

To have many instances of Redis running, you just need 1 binary, but you need to start it with different configurations. That’s what we’ll do.

All our instances share the same basic configuration, except for a few settings : the path of the dump.rdb and pid files, which TCP port or unix socket to use.

Let’s copy the default config file :

$ cp /usr/local/etc/redis{,-common}.conf

In our case we use unix sockets so in this common config file set port 0 the disable the use of TCP ports.

Then we can edit a /usr/local/etc/redis-1.conf with only these values :

include /usr/local/etc/redis-common.conf
pidfile /usr/local/var/run/redis-1.pid
unixsocket /tmp/redis-1.sock
dbfilename dump-1.rdb
vm-swap-file /tmp/redis-1.swap

We can copy this file for each instance we want, and just change the values. All the common configuration is shared. That’s up to you to decide which setting is shared and which is not. And as far as I know, you can override any setting in any configuration file, since the common config file is included at the top.

Now we need to launch those instances. Homebrew gives us a default file (homebrew.mxcl.redis.plist) :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>homebrew.mxcl.redis</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/redis-server</string>
      <string>/usr/local/etc/redis.conf</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>UserName</key>
    <string>jlecour</string>
    <key>WorkingDirectory</key>
    <string>/usr/local/var</string>
    <key>StandardErrorPath</key>
    <string>/usr/local/var/log/redis.log</string>
    <key>StandardOutPath</key>
    <string>/usr/local/var/log/redis.log</string>
  </dict>
</plist>

The basic principle of Launchd is that if you load such a file, Launchd will take care of it. In this case it starts Redis after boot, makes sure that it is restared if the process dies, runs it with a specific user and with some arguments (the config file for example).

We will copy this file for each instance we want and change the values in it. Here is a ~/Library/LaunchAgents/custom1.redis.plist :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>KeepAlive</key>
    <false/>
    <key>Label</key>
    <string>custom1.redis</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/redis-server</string>
      <string>/usr/local/etc/redis-1.conf</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>UserName</key>
    <string>jlecour</string>
    <key>WorkingDirectory</key>
    <string>/usr/local/var</string>
    <key>StandardErrorPath</key>
    <string>/usr/local/var/log/redis-1.log</string>
    <key>StandardOutPath</key>
    <string>/usr/local/var/log/redis-1.log</string>
  </dict>
</plist>

You see, we’ve just changed a couple of values.

Then we can load all these Launchd files :

$ launchctl load -w ~/Library/LaunchAgents/custom*.redis.plist

If you want to automate the start/stop of all your Redis instances, you can put this into your shell :

alias redis_start='launchctl load -w ~/Library/LaunchAgents/custom*.redis.plist'
alias redis_stop='launchctl unload -w ~/Library/LaunchAgents/custom*.redis.plist'

Restore production/backup data

Now that we have separate instances, just like on our production environment, we can restore the data for any of them, at any time. We just have to stop our local instance, replace the dump file with the one downloaded from our backup or production server and restart the local instance.

Since the dump file is just a persistence of the data Redis keeps in memory, it’s really important to stop the instance before you replace the dump file.
If you don’t do this and don’t restart the instance, it will never pick the “new” data up. If you restart the instance after you replaced the dump file, Redis will first dump it’s memory data into the file and replace the “new” date.

What have we done?

  • disabled the Launchd management of Redis as provided by Homebrew;
  • made separate config files for each instance (with shared settings to keep the maintainance simple)
  • made custom launchd files
  • imported a backup locally
Publié dans Autrement, Informatique, Mac | Tagué , , , | Poster un commentaire

Redis et la séparation des données entre les projets

Le 24 avril, Geoffrey Grosenbach demandait si on utilise des bases Redis (internes à une instance du serveur) différentes pour chaque projet, ou bien une seule, en espérant qu’il n’y ait pas de collision de clés. Cet article présente la manière de faire que j’ai adopté.

Rappel

Redis est une base de données “clés/valeurs”. C’est une manière de stocker et accéder aux données très différente des système relationnels tels que MySQL, Oracle, …

Pour comprendre le fonctionnement de Redis, je conseille la lecture du livre de Karl Seguin : The Little Redis Book.

Le serveur Redis (redis-server) est une application autonome, qui fonctionne avec un seul thread, accessible via un port TCP ou bien un socket système.

Il dispose de plusieurs bases internes, dont la seule distinction est un numéro d’ordre. Il y en a 16 par défaut (c’est configurable) et si le client ne spécifie pas de base particulière, il est connecté à la première (numérotée 0).

Au sein d’une base, Redis stocke des objets typés (les valeurs), accessibles par un index unique (les clés). Une clé est une simple suite de caractère, par exemple “metrics:users:count”. Le choix du “:” comme séparateur “sémantique” est totalement arbitraire et laissé au choix du développeur et permet de facilement reconstituer mentalement une arborescence de clés. Aux yeux de Redis, l’exemple précédent est strictement identique à “metrics/users/count”, “MetricsUsersCount” ou même “hello”.

Séparer ses données

Lorsqu’on manipule des données dans des contextes différents le risque est de contaminer les données d’un contexte depuis un autre contexte. Il convient alors d’utiliser un système qui permet de ne pas mélanger les données selon le contexte. Pour un projet qui peut fonctionner dans des environnements de test, développement et de production, les données doivent être partitionnées.
Si on a plusieurs projets en simultané, il faut également séparer leurs données.

La première approche est d’utiliser un espace de nommage. Encore une fois, pour Redis ça n’est pas une fonction particulière, mais juste une convention de nommage des clés. On peut alors préfixer nos clés par le nom du projet et son environnement : “projet1:dev:metrics:users:count” sera alors bien séparé de “projet2:prod:metrics:users:count”.

Le problème avec cette approche est que pour Redis, tout est dans le même panier. Il devient impossible de supprimer toutes les clés du “projet 1” uniquement. De même parcourir le contenu de la base à la recherche d’une clé est moins facile.

On peut alors utiliser une base interne différente pour chaque projet. Il conviendra alors au client de se connecter à la bonne base, mais ensuite tout est bien séparé.

Le problème est que Redis ne permet pas de nommer les bases internes, elles sont simplement numérotées. Il n’y a pas non plus de configuration particulière pour les bases (persistance, sécurité, …). Rien n’empêche un client de se connecter à la mauvaise base d’y mettre la pagaille.

De plus, le support des bases internes multiples va être déprécié ne sera pas supporté dans Redis Cluster, il est donc prudent d’étudier une autre alternative.

Il reste une troisième solution ; 1 serveur Redis par projet.

Configurer et utiliser plusieurs instances

Le serveur Redis est un simple binaire qui n’a aucun mal a être lancé plusieurs fois en parallèle. Par défaut il va chercher sa configuration à un emplacement prédéfini, mais rien n’empêche de le lancer avec une configuration spécifique à chaque fois.

Les variations minimales à faire entre les configurations sont au moins le moyen d’accéder à l’instance (port TCP ou socket système) et l’emplacement des données.

Il suffit de créer un fichier de configuration et un script d’initialisation pour chaque instance et le tour est joué.

Le choix d’en faire une pour chaque environnement au sein d’un même projet n’est pas si compliqué :

  • sur un serveur il n’y a le plus souvent que l’instance de “production” ;
  • sur le poste d’un développeur, il peut y avoir une instance de “développement” (permanente ou lancée au besoin) ;
  • pour un environnement de “test”, on peut avoir une instance démarrée à la volée, sans persistance sur le disque. Elle est donc re-initialisée à chaque fois, ce qui convient assez bien à ce type d’usage ;

Avantages des instances multiples

Il existe plusieurs grands avantages à utiliser Redis de cette manière

Une séparation stricte des données ; une fois connecté à un serveur, seules les données qu’il gère sont accessibles, sans risque de pollution. La sauvegarde/copie/déplacement des fichiers de persistance devient triviale, le vidage éventuel d’une base devient sans risque pour les autres données.

Une configuration adaptée ; il est possible de gérer la persistance des données de manière différente pour chaque instance, mais aussi d’utiliser un socket système pour certaines et un port TCP pour d’autre, des protections par authentification (ou pas), ou tout autre paramètre de configuration.

Une utilisation à la demande ; il est possible de ne lancer telle ou telle instance du serveur que lorsque c’est nécessaire. Sur un serveur en production, elles seront probablement toutes lancées en même temps, mais en développement ou sur un serveur d’intégration continue ça peut être utile (avec Foreman par exemple).

Une supervision spécifique ; on peut mettre en place des outils de supervision adaptés à chaque instance en fonction de son niveau de criticité. Une instance critique pourra être suivie de très près (y compris avec des tests sur la présence de clés/valeurs spécifiques), avec des graphiques exhaustifs sur les ressources, … Dans le même temps, une autre instance pourra être simplement testée sur le fait que son processus est bien présent et rien d’autre.

Il est important de noter que chaque instance du serveur Redis n’occupe qu’environ 1 Mo de ram (hors données stockées). le surcoût est donc minime, voire négligeable.

Conclusion

À partir du moment où plus d’un projet doit accéder à une base de données Redis, je ne vois que des avantages à disposer d’une instance de redis-server pour chaque projet.

Publié dans Informatique, PLUG | Tagué | 2 Commentaires

Sauvegarder une branche git, sans empêcher les rebase

Je suis assez régulièrement dans une situation où je travaille sur une branche de longue durée (plus de quelques jours), appelons la big_feature.

Pour maintenir cette branche à jour par rapport à master, j’utilise de préférence git rebase (par rapport à git merge).

Ça donne par exemple :

$ git checkout big_change
$ git rebase master

Le problème est que si je pousse ma branche big_change sur un dépôt distant, les “rebase” deviennent dangereux. Mais si je ne pousse jamais cette branche, et que je perds le contenu de mon dépôt local, alors je perds tout mon travail sur cette branche.

Évidemment, tout développeur sérieux dispose de sauvegardes de son poste de travail, mais selon les outils il peut être fastidieux d’y accéder juste pour quelques fichiers. Et puis il y a ceux qui n’ont aucune sauvegarde (les fous !). Pourquoi ne pas utiliser Git pour ça ?

Je me suis donc créé un petit script (accessible depuis mes dépôts) qui me permet de pousser ma branche courante sur un dépôt distant (origin par convention, modifiable en ajoutant un paramètre à l’appel du script), mais de manière à identifier qu’elle n’est qu’à des fins de sauvegarde.

#!/bin/sh
set -e
CUR=`git branch | grep '\*' | awk '{print $2}'`
REM=${1:-'origin'}
git push --force ${REM} ${CUR}:backup/${USER}/${CUR}

On trouvera donc sur le dépôt distant, un groupe de branches appelées “backup”, puis un sous-groupe pour chaque développeur, dans lequel il y trouvera ses branches de sauvegardes, nommées comme ses branches locales.

Ça crée donc une convention, facile à comprendre.

Plus généralement, si il y a un ou plusieurs “/” dans le nom d’une branche, Git va traiter ça comme des portions d’arborescence de système de fichier et grouppera donc toutes les branches dans les mêmes dossiers et éventuellement sous-dossiers.

J’utilise ce système pour toutes les branches qui correspondent à des fonctionnalités, par exemple :

  • features/new_login
  • features/alternate_footer

Ainsi dans les outils (graphiques ou en mode texte), je vois ces branches groupées, voire même de manière arborescente. Si vous ouvrez le dossier “.git” de votre dépôt, vous verrez que Git crée réellement des dossiers et sous-dossiers dans “.git/refs/heads” et “.git/refs/remotes/xyz/” et les branches y sint de vrais fichiers appelés comme la dernière partie du nom donné à la branche.

Publié dans Informatique | Tagué , | 4 Commentaires

Répondre à une offre d’emploi ou de stage : les bonnes et mauvaises pratiques

En ce moment, je suis en situation de recrutement de stagiaires, et je l’ai été plusieurs fois ces dernières années. Je reçois et traite de nombreuses candidatures. Ça m’a permis de compiler cette série de bonnes et mauvaises pratiques que je retranscrit ici sous forme de conseils bienveillants.

Imaginons que vous êtes candidat, que ma société s’appelle BigCorp et que je m’adresse à vous.

Postuler ou pas ?

Arroser la planète entière avec votre CV n’a que peu de chances de vous trouver un travail.

Cherchez bien à identifier le profil recherché et voir si vous pensez correspondre.

Si le profil recherché est expérimenté dans la construction de sites web de e-commerce et que vous êtes en première année d’IUT informatique de gestion, sans réelle expérience personnelle, ou bien si c’est un administrateur système qui est recherché alors que vous avez juste un peu bidouillé votre PC à la maison, ne répondez pas. Vous gagnerez du temps et surtout vous en économiserez au recruteur. Imaginez que vous soyez pris sur un malentendu ; c’est perdant-perdant.

Le mail de réponse

Si vous connaissez l’identité du destinataire, indiquez la en début de message lorsque vous vous adressez à lui/elle. Pas de “Madame, Monsieur, Mademoiselle” si vous savez que c’est Martine Durand qui est responsable de recrutement.

Indiquez à quelle offre vous répondez (et si possible comment vous l’avez trouvée), car il peut y avoir plusieurs recrutements en même temps dans l’entreprise.

Soyez attentif à la forme de votre message : politesse, orthographe, phrases courtes et bien construites, … Vous perdez de sérieux points lorsque vous laissez traîner plus d’une ou deux fautes d’orthographe dans votre message, lorsque la ponctuation est très mal (ou pas) utilisée, …

L’idéal est de coller au style de l’annonce sur le niveau de langage, le style de phrases, … Ça n’est pas simple, mais vous marquerez des points si c’est remarqué.

J’ai tendance à préférer l’expression de la motivation d’un candidat dans ce mail de réponse plutôt qu’un message presque vide et une pièce jointe “Lettre de motivation”.

Soyez original(e) si vous pensez que ça peut s’y prêter. Il n’est pas interdit de sortir du cadre des conventions classiques. Les meilleurs recrutements que j’ai fait sont souvent des personnes qui ont sur se différencier par le fond et la forme. Par contre c’est un exercice difficile car on peut aussi totalement tomber à côté de la plaque.

La “lettre de motivation”

Son but est de montrer que vous avez envie d’intégrer l’entreprise qui recrute et que vous lui apporterez ce qu’elle attend.

Ne sortez pas les phrases toutes faites, apprises à l’école. N’expliquez pas au recruteur ce qu’il sait déjà de son entreprise, surtout si c’est pour dire n’importe quoi (“Votre entreprise, leader sur son marché et son territoire” lorsque c’est une PME de 3 salariés). Trouvez d’autres moyens pour montrez que vous avez fait des recherches sur l’entreprise. Si elle dispose d’un blog, vous y trouverez des infos pertinentes pour comprendre la culture de l’entreprise, qui y travaille, …

Énumérer vos qualités risque de rapidement tomber dans les “sens des responsabilité”, “qualité relationnelle”, … qu’on attend presque toujours chez tout candidat. Indiquez plutôt ce qui peut vous démarquer au niveau de vos expériences, de votre parcours, … et qui est particulièrement adapté à l’entreprise.

Si vous y croyez, expliquez pourquoi vous pensez que n’êtes pas simplement “bon pour le poste”, mais le/la meilleur. Si vos arguments sont bons, ça ne passera pas pour de l’égocentrisme et de la vanité.

Le CV

Le CV est un piège dans lequel il est facile de tomber car les écoles nous apprennent souvent à faire des mauvais CV.

Soyez succinct ; le plus souvent 1 seule page suffit et pour ça il convient de bien choisir ce qu’on met en avant.

Tous les logiciels que vous avez utilisé, tous les micro-stages dans des entreprises qui n’ont rien à voir avec l’offre, le baby-sitting, … n’ont pas besoin de se trouver sur votre CV. Idem pour les hobbies personnels, mentionnez les s’il vous reste de la place.

Choisissez ce qui correspond particulièrement au profil du poste, quitte à mentionner que ça n’est pas tout et que seriez ravi de discuter de vos diverses expériences en annexes.

Si votre profil vous permet de postuler plusieurs offres, personnalisez un CV par poste, pour être bien ciblé.

Dans sa forme, un CV doit être sobre et très lisible. Si vous mettez une couleur ou un motif de fond, 3 polices de caractères différentes, des encadrés autour de chaque paragraphe, … vous vous y prenez mal.

Il conseillé d’annexer (directement ou avec un lien) un échantillon de vos précédentes réalisations, pourvu que ça soit adapté au poste pour lequel vous postulez. Si vous êtes développeur, indiquez ce qui est consultable en ligne (compte GitHub ou autre), un portfolio si vous êtes graphiste, …

Les pièces jointes

Format des fichiers

Il est indéniable que Microsoft Word est très répandu (bien que je doute que la plupart étudiants ait une licence valide), mais ça n’est pas non plus le standard.

J’ai le droit de ne pas vouloir payer plusieurs centaines d’Euros pour une licence entreprise de ce produit, ou bien d’utiliser un système sur lequel il n’est pas disponible. En m’imposant ce format propriétaire, vous réduisez les chances que je puisse consulter votre candidature.

Il existe cependant des formats libres, plus ouverts, et encore plus répandus.

  • le texte brut : c’est assez rustique, mais la solution ultime en terme d’accessibilité. Le plus souvent, un CV n’a pas besoin de faire preuve d’une grande créativité en terme de mise en forme. Si vous êtes dans des métiers de l’image, créez des documents adaptés : animés ou statiques selon, mais qui correspondent au destinataire.
  • le RTF : il permet une mise en forme plus riche, il est tout à fait standard et tous les logiciels de traitement de texte savent lire et exporter ce type de document.
  • le PDF : bien que format pas totalement libre, il existe des “lecteurs de PDF” pour quasiment tous les systèmes. Il a l’avantage de permettre une mise ne forme très poussée, une bonne accessibilité s’il est bien construit, peut être imprimé sans dégradation de format, …

Nom de chaque document

Le plus souvent, lorsqu’une entreprise publie une offre, elle ne reçoit pas seulement votre candidature.

Des documents qui s’appellent “CV.doc”, “LM.doc”, “profil.doc” ou encore “modèle.doc” deviennent totalement anonymes lorsqu’ils sont sortis du contexte du mail auquel ils étaient joints. Je classe tous ces documents dans un dossier correspondant au recrutement en cours. Il m’est donc beaucoup plus utile d’avoir des fichiers du genre “John Doe – CV.pdf”, “John Doe – LM BigCorp.pdf”.

  • votre nom en début permet de grouper plusieurs documents vous concernant lors d’un tri alphabétique.
  • indiquez ensuite le type de document s’il y en a plusieurs.
  • si votre lettre de motivation est personnalisée (fortement conseillé), indiquez le nom de l’entreprise destinataire, ça montre un effort d’adaptation.

Conclusion

Avec un minimum d’effort, c’est finalement assez facile de ne pas faire mauvaise impression lorsqu’on postule à une offre d’emploi ou de stage. Et si vous faîtes cet effort, vous serez probablement remarqué(e) et vous marquerez de précieux points lorsqu’il faudra décider de ne pas faire passer votre candidature dans la corbeille, mais à l’étape suivante de la sélection.

Mise à jour (31/11/2011) : Sur son blog, J-Mad complète judicieusement mes conseils.

Publié dans Informatique | Tagué , | Poster un commentaire

Tutorat technique : tiens, c’est cadeau !

Je fais partie de ceux qui croient que lorsqu’on débute ou qu’on cherche à se perfectionner dans une pratique, être accompagné d’un "mentor" (ou tuteur, si vous préférez) est une grande aide.

J’ai pu en bénéficier quelques fois à mes débuts (trop peu à mon goût, d’ailleurs) et ça m’a beaucoup servi.

C’est pourquoi je voudrais consacrer un peu de mon temps, régulièrement (et gratuitement), pour accompagner des personnes qui souhaiterais avoir un œil extérieur sur leur code, leurs pratiques, leurs méthodes, leurs outils, …

Il ne s’agit pas de formation au sens institutionnel du terme, mais plutôt d’observation, de critique et de conseil, dégagé de tout troll (dans la mesure du plus possible).

Je propose donc de passer 30 minutes à 1h en tête-à-tête, lors de chaque réunion du PLUG, avec une personne pour une séance de pair-programming, ou de discussion technique sur un sujet, … Ça peut être sur mes technos de prédilection, mais aussi sur n’importe quel langage, framework, … ou sur des méthodes de travail car il ne s’agit pas forcément de décortiquer le détail de chaque ligne, mais pourquoi pas d’avoir un regard critique d’ensemble, …

Faites moi signe (en commentaire, par e-mail, via Twitter, …) si vous êtes intéressé. On peut faire une tentative dès la prochaine réunion du PLUG, le 4 novembre. En cas de demandes multiples, je me réserve la liberté de choisir le sujet avec lequel je me sentirai le plus à l’aise ou le plus intéressé.

Mise à jour (21/11/2011) : La première tentative est concluante (pour moi au moins), donc je propose de recommencer dès la réunion du PLUG le 2 décembre.

Publié dans Informatique, laboate, Personnel, PLUG | Un commentaire

API Versioning in Rails with Accept HTTP headers

To implement API versioning in Rails, not using URL namespaces but custom MIME types, there are a few different approches.

The Tribesports way

Recently, I’ve seen a blog post about the Tribesports API. They chose to add a new MIME type to the application and use the rendering features of Rails.

Maybe I’ve not seen all the constraints they might have, and that lead to this choice, but from my point of view, 2 things are bothering me :

  1. they had to change too much things in the rendering process
  2. they created the api_v1 content type but in fact it’s plain JSON

What if they wanted to render JSON or XML but for the version 1 of their API ?

Another way

With a simple protected method in the ApplicationController, it’s possible to inspect the Accept HTTP header, and extract an API version number, while letting Rails decide what is the real content type to use.

class ApplicationController < ActionController::Base

  respond_to :html, :xml, :json

  protected

  def api_version
    default_version = '1'
    pattern = /application\/vnd\.com\.example\.api\.v([\d\.]+)\+.*/
    request.env['HTTP_ACCEPT'][pattern, 1] || default_version
  end
end

In this example, by default all the action method of all controllers will respond to HTML, XML and JSON, and Rails is probably using the default HTML if nothing is specified. I can even implement a rendering for another format in the respond_to block of a action method, like format.js for Ajax requests, …

We now have a method, accessible from all controller methods (including actions) to get the desired API version nummber. If an "application/vnd"-style Accept header is found and if a version number can be extracted, then it is used. There is a fallback to the default version.

With this, you can have any test you want at the controller level on the API version, without messing with the content type.

About the default version number, some prefer the lastest (and allow clients to set a specific version), and some prefer the first version. I prefer the "latest by default" way.

NB : I’m quite sure I’ve not made this one up, but I honestly can’t remember where I’ve read this from.

Publié dans Informatique | Tagué , , , , | 4 Commentaires