Comme tous les services Google, GSheet est accessible via API. Et comme toute API, google proposer un sdk de helper pour vous faciliter la vie.
Cependant, cette évidence amène un ensemble de soucis auxquels mon équipe et moi on a dû faire face récemment, alors je vous propose ce petit "truc et astuce" pour vous aider à lire/écrire des Google Spreadsheets avec java.
Ma principale motivation à en faire un billet est que des dizaines de tuto existent sur internet pour faire ça. Ils ont tous néanmoins deux faiblesses majeures :
- ils reposent sur l’idée que vous allez pouvoir demander à vos utilisateurs de valider l’accès avec leur navigateur
- ils utilisent les API de 2015, qui sont toutes dépréciées
Du coup, je me dis qu’un petit billet en Français avec un code à jour, ça peut être utile.
OAuth -tu là?
L’ensemble des applications Google reposent sur OAuth. L’identification se fait via leur IAM interne qui est branché à votre compte google perso ou d’entreprise.
Comme le permet OAuth, plusieurs flux d’authentification existent, ceux qui vont nous intéresser aujourd’hui sont ceux que google appellent le flux "InstalledApp" et le flux "Service User" qui est une implémentation de "Implicit Grant".
Ce billet se concentre sur ces deux méthodes car elles seront les plus utilisées en Java.
InstalledApp Flow, la base pour votre application
Se préparer
L’installedApp Flow est le mode d’utilisation à mettre en place si vous avez un client lourd ou une application mobile. La raison à cela est que l’application va devoir demander à ce que vous ouvriez le navigateur pour sélectionner votre utilisateur.
Avant de coder, nous allons donc aller dans l’interface d’admin du google workspace. Une fois cela fait, il faudra absolument créer une application.
C’est bien une application qu’il faudra créer, en précisent si c’est une app web ou pas, mais surtout pas une simple clef d’API. Ces dernières ne pourront qu’accéder en lecture aux feuilles publiques, jamais aux feuilles privées.
Une fois votre credentials OAuth créé, vous allez devoir télécharger le json qui lui est associé. Le mettre dans les ressources de votre projet java.
Coder
Maintenant vous pouvez créer votre projet java.
Si vous utilisez maven, ajoutez ces dépendances à votre pom :
A partir de là, vous allez pouvoir mettre en place le code fourni par tous les tutos du monde. Je vous propose le code pour la lecture :
Quelques remarques
Déjà les API sont complètes, et parfois redondées. On peut avoir les valeurs à partir des sheets comme je l’ai fait ou à partir d’autres endpoints.
Ensuite, côté fonctionnement, si vous mettez un identifiant de feuille correct, vous allez être invité à vous connecter à votre compte google puis le système va la lire.
Pour détecter que vous vous êtes connecté, le système a créé un listener qui va écouter un port de retour sur lequel votre navigateur va envoyer une requête en résultat de votre authentification.
Et là, c’est le drame :
- le listener a du mal à s’arrêter même quand on fait "stop", ce qui force à avoir le port en écoute tout le temps.
- cela signifie que votre application doit être installée sur la même machine que votre browser
- vous ne pouvez pas faire de tâche en fond avec ce système.
C’est pour ça qu’on va devoir passer à la suite : les comptes de service.
Compte de service et GSheet
Le but de mon équipe est de pouvoir consommer des GSheet en backend, on ne peut donc pas demander à un utilisateur d’aller sur son navigateur dès qu’on a besoin d’accéder à une sheet.
L’astuce consiste à utiliser les comptes de service et c’est là que les tutos sur internet sont à la ramasse.
Il vous faudra d’abord créer le compte de service et le lier aux credentials OAuth précedemment créés.
Une fois cela fait, un nouveau fichier json devra être téléchargé. Si vous êtes curieux vous verrez que la structure est un peu différente :
- tous les champs sont à la racine
- il y a des clefs privée : il faut donc absolument sécuriser ce fichier
Vous pouvez retirer le fichier précédemment ajouté à vos ressources, ça ne sert plus à rien.
Par contre, pour commencer à tester, il va falloir setter la variable d’environnement GOOGLE_APPLICATION_CREDENTIALS
pour qu’elle pointe vers notre nouveau fichier json.
Le code précédent va simplement être changé au niveau de la fonction credentials, mais avant ça il faut… ajouter deux dépendances (ça serait pas drôle sinon) :
On va pouvoir changer notre méthode :
Et voilà.
ça marche pas
Ah mais oui, j’ai oublié un détail, maintenant il va falloir que votre utilisateur de service ait accès aux documents. Pour cela deux possibilités :
- lui donner un à un les accès aux documents et dossiers via le partage. Son nom est trouvable dans le fichier json, dans l’attribut
client_email
; - faire un domain-level delegation dans votre console d’administration.
Maintenant ça marche.
Je suis vraiment obligé d’utiliser la variable d’environnement
Oui et non (tu aimes?). Globalement une variable d’environnement aide à la dockerisation car du coup c’est facilement configurable.
Notre équipe a choisi de stocker les credentials dans un vault pour lequel nous avons une API qui retourne un InputStream
. Au lieu de faire getApplicationDefault
il suffit alors de faire fromStream
et le tour est joué.