čtvrtek 14. listopadu 2013

Google Analytics API s Grails

Dělám teď na aplikaci, kde chci získat data z Google Analytics jako počet návštěvníků nebo statistiku nejnavštěvovanějších URL. Protože už jsem něco zkoušel s API od Google jako mapy, platby nebo grafy, tak si říkám, že to nemůže být tak těžké. Omyl. Bylo to docela komplikované to správně rozběhnout v Grails.

Konkrétně jsem potřeboval rozběhnout Reporting API (v3). Na Google mají návod, jak udělat "Hello World" pro tohle API. S největším problémem jsem se setkal už na začátku při získávání těch správných knihoven a jejich závislostí. Google samozřejmě má pro tohle zase jiný návod, kde je napsaný asi bambilion potřebných knihoven, kdybych to měl stahovat postupně. To se samozřejmě dnes už nedělá, ale používá se Maven nebo podobný buidovací nástroj (pro Grails je to Apache Ivy). Funguje to hodně podobně jako Maven, jen má jinou syntaxi, takže se lze řídit návodem pro Maven. Google vás zase odkáže na další stránku s návodem, tentokrát i s ukázkovou aplikací pro Javu s pom.xml (Maven soubor).

Po rozbalení ukázkové aplikace v souboru pom.xml zjistíte, že jsou potřeba tyto knihovny:

      <dependency>
      <groupId>com.google.apis</groupId>
      <artifactId>google-api-services-analytics</artifactId>
      <version>v3-rev74-1.17.0-rc</version>
    </dependency>
    <dependency>
      <groupId>com.google.http-client</groupId>
      <artifactId>google-http-client-jackson2</artifactId>
      <version>${project.http.version}</version>
    </dependency>
    <dependency>
      <groupId>com.google.oauth-client</groupId>
      <artifactId>google-oauth-client-jetty</artifactId>
      <version>${project.oauth.version}</version>
    </dependency>

Knihovna oauth-client je potřeba, jen pokud potřebujete, aby aplikace mohla žádat uživatele o přístup k jejich Google Analytics (něco jako Facebook přihlášení). To jsem ale nepotřeboval, protože chci získat data jen z vlastní Analytics, takže stačí 2 knihovny + klíčový soubor. Převedeno do Grails pro soubor BuildConfig.groovy, tak je to něco takového:

dependencies {
    def googleLibVersion = "1.17.0-rc"
    compile("com.google.apis:google-api-services-analytics:v3-rev74-${googleLibVersion}")
    compile("com.google.http-client:google-http-client-jackson2:${googleLibVersion}")
}

Jenže tohle nejde zkompilovat, chyba je následující:

:: commons-codec#commons-codec;1.6: configuration not found in commons-codec#commons-codec;1.6: 'master'. It was required from org.apache.httpcomponents#httpclient;4.0.1 compile

Po chvíli googlování (žádné řešení jsem nenašel), tak jsem to změnil na tohle:

def googleLibVersion = "1.17.0-rc"
build("com.google.apis:google-api-services-analytics:v3-rev74-${googleLibVersion}")
build("com.google.http-client:google-http-client-jackson2:${googleLibVersion}")

Následně jsem jen postupoval podle návodu od Google (triviální) a napsal jsem i nějaké testy, vše funguje tak, jak má. Když jsem ale zkompiloval aplikaci do .WAR a nasadil na produkční server, tak se aplikace nespustila a v logu byla chyba:

Caused by: java.lang.NoClassDefFoundError: com.google.api.client.json.jackson2.JacksonFactory

Z toho bylo jasné, že nejspíš chybí nějaká knihovna z Analytics, protože nic jiného od Google zatím nepoužívám. Zjistil jsem, že chyba je při změně z scope compile na build. Po přečtení odpovědi ze StackOverflow vyplynulo následující:

build - knihovna je k dispozici jen při buildování aplikace a není k dispozici při běhu
runtime - opak build - knihovna je k dispozici jen při běhu, ale není k dispozici při buildování (např. různé implementace JDBC pro konkrétní databáze).
compile - knihovna je k dispozici jak při buidování, tak i při běhu

Musel jsem tedy změnit scope na compile, jinak to nejde. Chybu s commons-codec jsem pak vyřešil pomocí příkazu grails dependency-report, který vám umožní vygenerovat si graf závislostí a případných konfliktů. Zjistil jsem, že commons-codec je už standardně v Grails, a je tedy potřeba zakázat Google, aby stahoval znova tuto knihovnu. Toho lze dosáhnout následujícím způsobem:

        def googleLibVersion = "1.17.0-rc"
        compile("com.google.apis:google-api-services-analytics:v3-rev74-${googleLibVersion}") {
            excludes "commons-codec"
        }
        compile("com.google.http-client:google-http-client-jackson2:${googleLibVersion}") {
            excludes "commons-codec"
        }

A tohle už funguje správně.

TL;DR:
Pokud chcete použít Google Analytics Reporting API (v3), potřebujete knihovny. Zkopčete si následující řádky do BuildConfig.groovy:

dependencies {
        def googleLibVersion = "1.17.0-rc"
        compile("com.google.apis:google-api-services-analytics:v3-rev74-${googleLibVersion}") {
            excludes "commons-codec"
        }
        compile("com.google.http-client:google-http-client-jackson2:${googleLibVersion}") {
            excludes "commons-codec"
        }
}