Préface
Mon application Web stocke des données dans
localStorage
. C'Ă©tait pratique jusqu'Ă ce que je veuille que l'utilisateur voit la mĂȘme chose lorsqu'il accĂšde au site Ă partir de diffĂ©rents appareils. Autrement dit, un stockage Ă distance Ă©tait nĂ©cessaire.
Mais l'application est "hébergée" sur les pages GitHub et n'a pas de partie serveur. J'ai décidé de ne pas créer de serveur, mais de stocker les données avec un tiers. Cela donne des avantages importants:
- Pas besoin de payer pour le serveur, cela ne fait pas de mal Ă la tĂȘte quant Ă sa stabilitĂ© et sa disponibilitĂ©.
- Moins de code, moins d'erreurs.
- L'utilisateur n'a pas besoin de s'inscrire dans mon application (c'est gĂȘnant pour beaucoup).
- La confidentialité est plus élevée et l'utilisateur sait que ses données sont stockées dans un endroit auquel il fait probablement plus confiance que moi.
Tout d'abord, le choix s'est
porté sur
remoteStorage.js . Ils offrent un protocole d'Ă©change de donnĂ©es ouvert, une trĂšs jolie API, la possibilitĂ© de s'intĂ©grer Ă Google Drive et Dropbox, ainsi qu'Ă leurs serveurs. Mais ce chemin s'est avĂ©rĂ© ĂȘtre une impasse (pourquoi - une histoire distincte).
Au final, j'ai décidé d'utiliser directement Google Drive et la
bibliothÚque cliente Google API (ci-aprÚs GAPI) comme bibliothÚque pour y accéder.
Malheureusement, la documentation de Google est dĂ©cevante, et la bibliothĂšque GAPI semble inachevĂ©e, d'ailleurs, elle a plusieurs versions, et on ne sait pas toujours laquelle est en cause. Par consĂ©quent, la solution Ă mes problĂšmes devait ĂȘtre collectĂ©e en morceaux Ă partir de la documentation, des questions et des rĂ©ponses sur StackOverflow et des publications alĂ©atoires sur Internet.
J'espÚre que cet article vous fera gagner du temps si vous décidez d'utiliser Google Drive dans votre application.
La préparation
Voici une description de la façon d'obtenir des clĂ©s pour travailler avec l'API Google. Si vous n'ĂȘtes pas intĂ©ressĂ©, passez directement Ă la partie suivante.
Réception des clésDans la console développeur de Google,
créez un nouveau projet, entrez un nom.
Dans le "Panneau de configuration", cliquez sur "Activer l'API et les services" et activez Google Drive.
Ensuite, accédez à la section API et services -> Informations d'identification, cliquez sur "Créer des informations d'identification". Il y a trois choses que vous devez faire:
- Configurez la "fenĂȘtre de demande d'accĂšs OAuth". Entrez le nom de l'application, votre domaine dans la section "Domaines autorisĂ©s" et un lien vers la page principale de l'application. Les autres champs sont facultatifs.
- Dans la section "Informations d'identification", cliquez sur "CrĂ©er des informations d'identification" -> "Identifiant client OAuth". SĂ©lectionnez le type «Application Web». Dans la fenĂȘtre des paramĂštres, ajoutez "Sources Javascript autorisĂ©es" et "URI de redirection autorisĂ©es":
- Votre domaine (obligatoire)
http://localhost:8000
(facultatif pour travailler localement).

- Dans la section "Informations d'identification", cliquez sur "Créer des informations d'identification" -> "Clé API". Dans les paramÚtres clés, spécifiez les restrictions:
- Type d'application autorisé -> référents HTTP (sites Web)
- Acceptez les demandes http provenant des sources de référence (sites) suivantes -> votre domaine et votre hÎte local (comme au point 2).
- API valides -> API Google Drive

La section des informations d'identification doit ressembler Ă ceci:

Nous y voilĂ . Nous passons au code.
Initialisation et connexion
La méthode recommandée par Google pour activer GAPI est de coller le code suivant dans votre code HTML:
<script src="https://apis.google.com/js/api.js" onload="this.onload=function(){}; gapi.load('client:auth2', initClient)" onreadystatechange="if (this.readyState === 'complete') this.onload()"> </script>
AprÚs avoir chargé la bibliothÚque, la fonction
initClient
sera appelĂ©e, que nous devons Ă©crire nous-mĂȘmes. Son aspect typique est le suivant:
function initClient() { gapi.client.init({
Pour le stockage des données, nous utiliserons le
dossier des données d'application . Ses avantages par rapport à un dossier ordinaire:
- L'utilisateur ne le voit pas directement: les fichiers qu'il contient n'obstruent pas son espace personnel et il ne peut pas ruiner nos données.
- D'autres applications ne le voient pas et ne peuvent pas non plus le gĂącher.
- La portée, mentionnée ci-dessus, donne accÚs à l'application, mais ne donne pas accÚs au reste des fichiers de l'utilisateur. Autrement dit, nous n'effrayerons pas une personne par des demandes d'accÚs à ses données personnelles.
Une fois l'initialisation de l'API Google réussie, la fonction effectue les opérations suivantes:
- Commence Ă attraper les Ă©vĂ©nements de connexion / dĂ©connexion - trĂšs probablement, cela devrait toujours ĂȘtre fait.
- Initialise l'application. Cela peut ĂȘtre fait avant de charger et d'initialiser GAPI - comme vous prĂ©fĂ©rez. Ma procĂ©dure d'initialisation Ă©tait lĂ©gĂšrement diffĂ©rente si Google n'Ă©tait pas disponible. Quelqu'un peut dire que cela ne se produit pas :) Mais, tout d'abord, vous pouvez ĂȘtre intelligent avec les clĂ©s et les droits d'accĂšs Ă l'avenir. DeuxiĂšmement, par exemple, en Chine, Google est interdit.
La connexion et la déconnexion se font simplement:
function isGapiLoaded() { return gapi && gapi.auth2 } function logIn() { if (isGapiLoaded()) {
Vous recevrez les résultats de connexion dans le gestionnaire
onSignIn
:
function isLoggedIn() { return isGapiLoaded() && gapi.auth2.getAuthInstance().isSignedIn.get() } function onSignIn() { if (isLoggedIn()) {
Malheureusement, travailler avec des fichiers n'est pas si évident.
Aide Ă la promesse
GAPI ne renvoie pas de promesses normales. Au lieu de cela, sa propre interface Thennable est utilisée, ce qui est similaire aux promesses, mais pas tout à fait. Par conséquent, pour la commodité du travail (principalement pour utiliser
async/await
), nous ferons un petit assistant:
function prom(gapiCall, argObj) { return new Promise((resolve, reject) => { gapiCall(argObj).then(resp => { if (resp && (resp.status < 200 || resp.status > 299)) { console.log('GAPI call returned bad status', resp) reject(resp) } else { resolve(resp) } }, err => { console.log('GAPI call failed', err) reject(err) }) }) }
Cette fonction prend la méthode GAPI et les paramÚtres comme premier argument et renvoie Promise. Ensuite, vous verrez comment l'utiliser.
Travailler avec des fichiers
Vous devez toujours vous rappeler que
le nom de fichier sur Google Drive n'est pas unique . Vous pouvez crĂ©er un nombre illimitĂ© de fichiers et de dossiers portant le mĂȘme nom. Seul l'identifiant est unique.
Pour les tĂąches de base, vous n'avez pas besoin de travailler avec des dossiers, donc toutes les fonctions ci-dessous fonctionnent avec des fichiers Ă la racine du dossier Application Data. Les commentaires indiquent ce qui doit ĂȘtre modifiĂ© pour fonctionner avec les dossiers. La documentation de Google est ici .
Créer un fichier vide
async function createEmptyFile(name, mimeType) { const resp = await prom(gapi.client.drive.files.create, { resource: { name: name,
Cette fonction asynchrone crĂ©e un fichier vide et retourne son identifiant (chaĂźne). Si un tel fichier existe dĂ©jĂ , un nouveau fichier du mĂȘme nom sera créé et son ID sera retournĂ©. Si vous ne le souhaitez pas, vous devez d'abord vĂ©rifier qu'il n'y a pas de fichier du mĂȘme nom (voir ci-dessous).
Google Drive n'est pas une base de donnĂ©es complĂšte. Par exemple, si vous souhaitez que plusieurs utilisateurs travaillent simultanĂ©ment Ă partir du mĂȘme compte Google Ă partir de diffĂ©rents appareils, il peut y avoir des problĂšmes de rĂ©solution des conflits en raison du manque de transactions. Pour de telles tĂąches, il est prĂ©fĂ©rable de ne pas utiliser Google Drive.
Travailler avec le contenu des fichiers
GAPI (pour JavaScript basé sur un navigateur) ne fournit pas de méthodes pour travailler avec le contenu des fichiers (trÚs étrange, n'est-ce pas?). Au lieu de cela, il existe une méthode de
request
gĂ©nĂ©rale (un wrapper fin sur une simple requĂȘte AJAX).
Par essais et erreurs, je suis arrivé aux implémentations suivantes:
async function upload(fileId, content) {
Recherche de fichiers
async function find(query) { let ret = [] let token do { const resp = await prom(gapi.client.drive.files.list, {
Cette fonction, si vous ne spécifiez pas de
query
, renvoie tous les fichiers du dossier d'application (un tableau d'objets avec des champs
id
et
name
), triés par heure de création.
Si vous spécifiez la chaßne de
query
(la syntaxe est décrite
ici ), elle renverra uniquement les fichiers correspondant Ă la requĂȘte. Par exemple, pour vĂ©rifier si un fichier nommĂ©
config.json
, vous devez faire
if ((await find('name = "config.json"')).length > 0) {
Suppression de fichiers
async function deleteFile(fileId) { try { await prom(gapi.client.drive.files.delete, { fileId: fileId }) return true } catch (err) { if (err.status === 404) { return false } throw err } }
Cette fonction supprime le fichier par ID et renvoie
true
s'il a été supprimé avec succÚs et
false
s'il n'y avait pas un tel fichier.
Sync
Il est conseillé que le programme fonctionne principalement avec
localStorage
, et Google Drive est utilisé uniquement pour synchroniser les données de
localStorage
.
Voici une stratégie de synchronisation de configuration simple:
- La nouvelle configuration est téléchargée à partir de Google Drive avec un identifiant, puis toutes les 3 minutes, en écrasant la copie locale;
- Les modifications locales sont versées sur Google Drive, écrasant ce qui s'y trouvait;
- le
fileID
configuration fileID
est mis en cache dans localStorage
pour accélérer le travail et réduire le nombre de demandes; - Les situations correctement gérées (erronées) sont lorsque Google Drive possÚde plusieurs fichiers de configuration et que quelqu'un a supprimé notre fichier de configuration ou l'a ruiné.
- Les détails de la synchronisation n'affectent pas le reste du code d'application. Pour travailler avec la configuration, vous n'utilisez que deux fonctions:
getConfig()
et saveConfig(newConfig)
.
Dans une application réelle, vous souhaiterez probablement implémenter une gestion des conflits plus flexible lors du chargement / déchargement d'une configuration.
Conclusion
Il me semble que le magasin de donnĂ©es d'un site Web sur Google Drive est idĂ©al pour les petits projets et le prototypage. Il est non seulement facile Ă mettre en Ćuvre et Ă prendre en charge, mais contribue Ă©galement Ă rĂ©duire le nombre d'entitĂ©s inutiles dans l'univers. Et mon article, je l'espĂšre, vous aidera Ă gagner du temps si vous choisissez ce chemin.
PS Le code du vrai projet
se trouve sur GitHub ,
vous pouvez l' essayer
ici .