Ou comment je me suis cassé les dents sur une documentation velue mais pas du tout claire.
La demande est simple : récupérer les avis Google de plusieurs établissements afin de les afficher sur une page web.
La compréhension du fonctionnement est ... moins simple.
En cherchant "google reviews api" dans notre moteur de recherche préféré, on tombe rapidement sur cette page de doc de Google, avec un joli message :
Ce message est plus ou moins affiché en haut de toutes les pages de la doc, que ces dernières soient obsolètes ou non. On comprend déjà que pour savoir si la demande est faisable et comment, il va falloir mettre les mains dans le cambouis et tester les APIs. De ce que j'ai compris entre 2 maux de tête : les endpoints de l'API Google My Business ont été partiellement remplacés par ceux de l'API Business Information le 30/04/2022. Ce qui veut dire qu'il faut se balader entre 2 URL pour arriver à récupérer les identifiants nécessaires (account
et location
) pour enfin pouvoir récupérer les reviews
. A noter que pour pouvoir appeler ces 2 APIs, il faut au préalable en appeler 2 autres pour récupérer un access_token.
N'ayant trouvé aucune documentation Google expliquant de A à Z comment récupérer les reviews, je me suis basée sur cet article de blog malheureusement déjà obsolète et de ces étapes listées par un employé de Google pour arriver à comprendre comment faire.
Voici le process qui en a résulté :
Dans la console Google Cloud :
- Aller dans API et services > Identifiants
- Cliquer sur Créer des identifiants et sélectionner ID client OAuth dans la liste des options disponibles
- Type d'application : sélectionner Application Web dans la liste déroulante
- Nom : saisir un nom pour votre client OAuth 2.0 afin de l'identifier dans la console Cloud
- Sous URI de redirection autorisée, cliquer sur + Ajouter un URI et renseigner une URL (dans notre cas, la page doit simplement être accessible et ne pas planter si on va dessus avec des paramètres GET "aléatoires")
- Cliquer sur Créer
Un ID client OAuth 2.0 a été créé.
Garder dans un coin l'ID client ({CLIENT_ID}), le Code secret du client ({CLIENT_SECRET}), et l'URI de redirection autorisés ({REDIRECT_URL})
Dans un navigateur web, rentrer l'URL suivante en remplaçant {REDIRECT_URL} et {CLIENT_ID} par les valeurs précédemment mises de côté :
https://accounts.google.com/o/oauth2/v2/auth?
redirect_uri={REDIRECT_URL}
&client_id={CLIENT_ID}
&prompt=consent
&scope=https://www.googleapis.com/auth/business.manage
&access_type=offline
&response_type=code
L'écran de consentement est affiché à l'utilisateur. Valider/autoriser. L'utilisateur est alors redirigé sur {REDIRECT_URL}, qui est suffixé par des paramètres GET. Parmi eux, récupérer la valeur de code (attention, ce code est temporaire et expire. Le délai n'est pas documenté).
Ce {code} va nous permettre de récupérer :
- le {refresh_token} : qui n'expire jamais quand l'app est en mode prod. Expire au bout de 7 jours en mode test. Ce token permet de récupérer un nouveau access_token
- un premier {access_token} : expire au bout d'une heure et permet d'appeler certaines API de Google.
Pour ce faire :
Exécuter un appel POST vers https://oauth2.googleapis.com/token
avec en body :
{
"code": "{code}",
"client_id": "{CLIENT_ID}",
"client_secret": "{CLIENT_SECRET}",
"redirect_uri": "{REDIRECT_URL}",
"grant_type": "authorization_code"
}
La réponse doit ressembler à :
{
"access_token": "ya29.a0AfB_blablablabla-blablablabla-GCj_Ldh5n_blablablabla-blablablabla-00aKkgrk8ZC8AZn8_blablablabla",
"expires_in": 3599,
"refresh_token": "1//blablablabla-blablablabla_blablablabla",
"scope": "https://www.googleapis.com/auth/business.manage",
"token_type": "Bearer"
}
Appeler en GET https://mybusinessaccountmanagement.googleapis.com/v1/accounts
avec le {ACCESS_TOKEN} en Authorization Bearer.
Exemple de réponse :
{
"accounts": [
{
"name": "accounts/123456789012345678901",
"accountName": "Nom du compte GMB",
"type": "PERSONAL",
"verificationState": "UNVERIFIED",
"vettedState": "NOT_VETTED"
}
]
}
Récupérer la suite de chiffres après accounts/
dans name
: 123456789012345678901
Appeler en GET https://mybusinessaccountmanagement.googleapis.com/v1/accounts/123456789012345678901/locations?read_mask=name,title
avec le {ACCESS_TOKEN} en Authorization Bearer.
Exemple de réponse :
{
"locations": [
{
"name": "locations/98765432109876543210",
"title": "Nom de la fiche établissement"
}
]
}
Récupérer la suite de chiffres après les locations/
dans name
: 98765432109876543210
N.B.: rajouter le paramètre GET pageSize=XX
si vous avez plus de 10 fiches établissements, XX étant le nombre de fiches que vous souhaitez récupérer.
Appeler en GET https://mybusiness.googleapis.com/v4/accounts/{ACCOUNT_ID}/locations/{LOCATION_ID}/reviews
avec le {ACCESS_TOKEN} en Authorization Bearer.
Et là, vous devriez avoir les avis dans la réponse !
{
"reviews": [
{
"reviewId": "review-encrypted-unique-identifier",
"reviewer": {
"profilePhotoUrl": "https://lh3.googleusercontent.com/a-/...",
"displayName": "Jane DOE"
},
"starRating": "FIVE",
"comment": "Accueil très chaleureux et toujours disponible quand on a des questions",
"createTime": "2023-09-24T12:51:23.896909Z",
"updateTime": "2023-09-24T12:51:23.896909Z",
"name": "accounts/{ACCOUNT-ID}/locations/{LOCATION-ID}/reviews/review-encrypted-unique-identifier"
},
{
...
},
...
],
"averageRating": 5,
"totalReviewCount": 17
}
De façon complètement autonome et non souhaitée, Google traduit les avis (dans notre cas, en anglais) et les injecte dans le texte de l'avis. Impossible de désactiver ce comportement. De plus, ces avis traduits peuvent avoir deux structures différentes.
Ce n'est pas terrible, mais pas le choix de tester le contenu pour essayer d'en extraire la version originale. Ce qui donne quelque chose du genre :
// Google is funny and adds an English translation in the comment without asking us if it is needed
// a translated comment can currently look like this :
// - "(Translated by Google)translated blabla\n\n(Original)\nblabla"
// - "blabla(Translated by Google)translated blabla"
// (with or without \n and/or carriage return around parenthesis)
\preg_match(
'#^(\(.*\\n\\n\(\D*\)\\n(?<originalComment>.*))|((?<originalComment2>.*)\(Translated by Google\).*)$#s',
$commentFromGoogle,
$matches
);
if (!empty($matches['originalComment'])) {
$finalComment = trim($matches['originalComment']);
} elseif (!empty($matches['originalComment2'])) {
$finalComment = trim($matches['originalComment2']);
} else {
// a comment is not always translated, so we take the comment given by the API if patterns don't match
$finalComment = $commentFromGoogle;
}
Il m'aura fallu pas moins de 5 jours pour arriver à comprendre et mettre en œuvre tout le nécessaire pour la mise en production de cette feature. Alors si je peux en aider quelques un.e.s avec cet article c'est cadeau <3