L’API PageSpeed v2

Dans cet article je vais revisiter l’article que j’avais écrit en mai 2012 sur l’utilisation de l’API PageSpeed de Google. Cette fois-ci c’est C++Builder XE7 qui sera utilisé avec la version 2 de l’API. Tout comme la première fois, les résultats seront présentés dans un diagramme circulaire à l’aide du contrôle TChart. En plus du code qui sera légèrement différent, un composant TImage sera utilisé pour y afficher une capture d’écran du site web.

La première étape est de créer un nouveau projet FireMonkey. Dans la Form il faut insérer un TRESTClient, un TRESTRequest, un TRESTResponse, un TChart, un TImage et un TLayout dans lequel il y aura un TEdit un TButton. On aligne le contrôle TLayout à Bottom et vous pouvez donner comme texte à votre bouton le mot « Analyser ».

Voici ce à quoi l’interface devrait ressembler:
Analyseur de site web

Dans votre fichier cpp voici la liste de fichier d’en-tête à utiliser ainsi que la macro qui va contenir votre clef d’API. N’essayez pas d’utiliser celle-ci, il s’agit de caractères écrits de façon aléatoire.

#include <System.JSON.hpp>
#include <FMXTee.Series.hpp>
#include <System.NetEncoding.hpp>
#define GOOGLEAPIKEY "dskk1j3sW4WBYdkjds8sSDSD" // Clef d'API

Voici le code à ajouter dans votre constructeur:

    Chart1->Title->Text->Text = "Statistique de la page";
    Chart1->Legend->Title->Text->Text = "Ressource en octets";
    Chart1->Legend->Alignment = TLegendAlignment::laBottom;
    Chart1->BevelOuter = TPanelBevel::bvNone;
    Series::TPieSeries *Series = new Series::TPieSeries(this);
    Series->Marks->Visible = false;
    Chart1->AddSeries(Series);

Étant donné que nous accéderons à un site web qui utilise SSL (https), les fichiers ssleay32.dll et libeay32.dll devront être distribués avec votre application Windows. Une version Win32 et Win64 des fichiers est disponible sur le site web suivant: http://indy.fulgan.com/SSL.

La prochaine étape est d’ajouter le code dans l’événement OnClick du bouton.

    Chart1->Series[0]->Clear(); // Efface le contenu du diagramme

    RESTClient1->BaseURL =
        "https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url=" +
        Edit1->Text + "&key=" GOOGLEAPIKEY + "&screenshot=true";
    RESTRequest1->Execute();

    TJSONObject* Obj = static_cast<TJSONObject*>(RESTResponse1->JSONValue);
    TJSONPair* Pair = Obj->Get("pageStats");
    if(Pair)
    {
        TJSONNumber* Answer;
        TJSONObject* PageStats = static_cast<TJSONObject*>(Pair->JsonValue);
        if((Pair = PageStats->Get("htmlResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONNumber*>(Pair->JsonValue);
            Chart1->Series[0]->Add(Answer->AsInt, "HTML", TAlphaColor(claGreen));
        }
        if((Pair = PageStats->Get("cssResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONNumber*>(Pair->JsonValue);
            Chart1->Series[0]->Add(Answer->AsInt, "CSS", TAlphaColor(claOrange));
        }
        if((Pair = PageStats->Get("imageResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONNumber*>(Pair->JsonValue);
            Chart1->Series[0]->Add(Answer->AsInt, "Image", TAlphaColor(claYellow));
        }
        if((Pair = PageStats->Get("javascriptResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONNumber*>(Pair->JsonValue);
            Chart1->Series[0]->Add(Answer->AsInt, "JavaScript", TAlphaColor(claRed));
        }
        if((Pair = PageStats->Get("otherResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONNumber*>(Pair->JsonValue);
            Chart1->Series[0]->Add(Answer->AsInt, "Autre", TAlphaColor(claBlue));
        }
    }
    Pair = Obj->Get("screenshot");
    if(Pair)
    {
        TJSONObject* Screenshot = static_cast<TJSONObject*>(Pair->JsonValue);
        if((Pair = Screenshot->Get("data")) != NULL)
        {
            TJSONString* Answer = static_cast<TJSONString*>(Pair->JsonValue);
            String Value = Answer->Value();
            // On change de base64url à base64
            Value = ReplaceStr(ReplaceStr(Value, "_", "/"), "-", "+");
            // On transforme de base64 vers stream
            TBytes LDAta = TNetEncoding::Base64->DecodeStringToBytes(Value);
            TBytesStream* LStream = new TBytesStream(LDAta);
            try
            {
                Image1->Bitmap->LoadFromStream(LStream);
            }
            __finally
            {
                delete LStream;
            }
        }
    }

Un petit mot sur la ligne 49. La documentation de l’API PageSpeed à propos des données de l’image dit:

Base64-encoded screenshot of the page that was analyzed.

Les données peuvent comporter des caractères moins (-) et souligné (_), donc la documentation est erronée si on se fie à RFC 4648 section 5:

This encoding may be referred to as « base64url ». This encoding should not be regarded as the same as the « base64 » encoding and should not be referred to as only « base64 ». Unless clarified otherwise, « base64 » refers to the base 64 in the previous section.

This encoding is technically identical to the previous one, except for the 62:nd and 63:rd alphabet character, as indicated in Table 2.

Google n’aurait donc pas dû dire qu’il s’agit de base64. Il aurait dû dire que c’est du base64url. C’est pour cette raison que je remplace les deux caractères.

Pourtant, dans d’autres API comme celui de Gmail, Google met la bonne information:

The entire email message in an RFC 2822 formatted and base64url encoded string.

En terminant, je vous rappelle qu’un nouvel outil dans RAD Studio XE7 vous permet de tester les API REST. Il se trouve Tools / Rest Debugger. Voici une capture d’écran du logiciel:
RESTDebugger

Utiliser l’API PageSpeed de Google avec C++Builder

PageSpeed est un outil développé par Google qui sert à analyser une page Web. Dans cet article il sera utilisé pour obtenir le nombre d’octets de chaque élément qui composent une page web. Les résultats seront présentés dans un diagramme circulaire à l’aide du contrôle TChart.

Avant de débuter, il faut aller sur le site de Google pour activer l’API Page Speed Online dans la section Services. Il vous faudra créer une clef d’API qui sera utilisée à chaque requête. Il est à noter que Google vous donne le droit d’exécuter 2500 requêtes par jour pour cet API.

Page Speed Online API ON
Page Speed Online API Activé

La première étape est de créer un nouveau projet FireMonkey HD. Dans la Form il faut insérer un TIdHTTP, un TIdSSLIOHandlerSocketOpenSSL, un TChart et un TLayout dans lequel il y aura un TEdit un TButton. On aligne le contrôle TLayout à alBottom et le TChart à alClient. Vous pouvez donner comme texte à votre bouton le mot « Analyser ».

Avant même de voir le code, je vous présente le résultat final. Ceci vous permettra de mieux comprendre vers où nous nous dirigeons.
Analyseur de site web

Dans votre fichier cpp voici la liste de fichier d’en-tête à utiliser ainsi que la macro qui va contenir votre clef d’API. N’essayer pas d’utiliser celle-ci, il s’agit de caractères écrits de façon aléatoire.

#include <Data.DBXJSON.hpp>
#include <FMXTee.Series.hpp>
#define GOOGLEAPIKEY "dskk1j3sW4WBYdkjds8sSDSD" // Clef d'API

Voici le code à ajouter dans votre constructeur:

    IdHTTP1->IOHandler = IdSSLIOHandlerSocketOpenSSL1;

    Chart1->Title->Text->Text = "Statistique de la page"; // Titre du diagramme
    Chart1->Legend->Title->Text->Text = "Ressource en octets"; // Titre de la légende
    Series::TPieSeries *Series = new Series::TPieSeries(this); // Diagramme circulaire
    Series->Marks->Visible = false; // Ce n'est pas nécessaire car on a déjà une légende
    Chart1->AddSeries(Series);

Étant donné que nous accéderons à un site web qui utilise SSL (https), la première ligne de code est critique. Sans elle, une exception dans la classe EIdIOHandlerPropInvalid produira le message « IOHandler value is not valid ». Parce que nous utilisons OpenSSL, les fichiers ssleay32.dll et libeay32.dll devront être distribués avec votre application.

Les lignes 3 à 7 servent à ajouter des informations au graphique.

La prochaine étape est d’ajouter le code dans l’événement OnClick du bouton.

    Chart1->Series[0]->Clear(); // Efface le contenu du diagramme

    String Response = IdHTTP1->Get(
        "https://www.googleapis.com/pagespeedonline/v1/runPagespeed?url=" +
        Edit1->Text + "&key=" GOOGLEAPIKEY);

    TJSONObject* Obj = static_cast<TJSONObject*>(TJSONObject::ParseJSONValue(Response));
    TJSONPair* Pair = Obj->Get("pageStats");
    if(Pair)
    {
        String Value;
        TJSONString* Answer;
        TJSONObject* PageStats = static_cast<TJSONObject*>(Pair->JsonValue);
        if((Pair = PageStats->Get("htmlResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONString*>(Pair->JsonValue);
            Value = AnsiDequotedStr(Answer->ToString(), '\"');
            Chart1->Series[0]->Add(Value.ToIntDef(0), "HTML", claGreen);
        }
        if((Pair = PageStats->Get("cssResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONString*>(Pair->JsonValue);
            Value = AnsiDequotedStr(Answer->ToString(), '\"');
            Chart1->Series[0]->Add(Value.ToIntDef(0), "CSS", claOrange);
        }
        if((Pair = PageStats->Get("imageResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONString*>(Pair->JsonValue);
            Value = AnsiDequotedStr(Answer->ToString(), '\"');
            Chart1->Series[0]->Add(Value.ToIntDef(0), "Image", claYellow);
        }
        if((Pair = PageStats->Get("javascriptResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONString*>(Pair->JsonValue);
            Value = AnsiDequotedStr(Answer->ToString(), '\"');
            Chart1->Series[0]->Add(Value.ToIntDef(0), "JavaScript", claRed);
        }
        if((Pair = PageStats->Get("otherResponseBytes")) != NULL)
        {
            Answer = static_cast<TJSONString*>(Pair->JsonValue);
            Value = AnsiDequotedStr(Answer->ToString(), '\"');
            Chart1->Series[0]->Add(Value.ToIntDef(0), "Autre", claBlue);
        }
    }

Les lignes 3 à 5 servent à appeler l’API et mettre la réponse dans la variable Response. Cette réponse utilise le format JSON (JavaScript Object Notation). Voici la section qui nous intéresse pour notre projet:

{
 "pageStats": {
  "numberResources": 89,
  "numberHosts": 11,
  "totalRequestBytes": "18788",
  "numberStaticResources": 72,
  "htmlResponseBytes": "511838",
  "cssResponseBytes": "127217",
  "imageResponseBytes": "399484",
  "javascriptResponseBytes": "396089",
  "otherResponseBytes": "4023",
  "numberJsResources": 19,
  "numberCssResources": 4
 }
}

Comme on peut le voir certaines valeurs numériques utilisent des guillemets doubles, c’est pour cette raison que nous utiliserons la fonction AnsiDequotedStr pour les enlever.

En terminant, je voulais juste vous faire une petite mise en garde. Faites attention de protéger votre clef d’API car il est très facile pour n’importe qui de la retrouver en regardant le contenu de votre fichier exécutable. Même pas besoin d’éditeur hexadécimal compliqué, il suffit du Bloc-notes comme démontré ici:
Fichier exécutable ouvert dans le Bloc-notes