ScalaでGoogle App Engine内からhttpリクエストをしようとして苦労した話

結論からいうと

「Scala2.10でGoogle App Engine内からhttpリクエスト投げるときは、scalaj-http0.3.6を使うとうまくいく」

versionがそれより古くても新しくてもだめ。

理由は

java.lang.NoClassDefFoundError: java.net.Proxy is a restricted class. Please see the Google  App Engine developer's guide for more details.
            at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:51)
            at scalaj.http.Http$Request$.apply$default$7(Http.scala:101)
            at scalaj.http.Http$Request$.apply(Http.scala:96)
            at scalaj.http.Http$.get(Http.scala:281)
            at scalaj.http.Http$.apply(Http.scala:90)

でさらにいうとdispatch-classic 0.8.10 使ってみたら以下のようなエラーになった。

 com.google.apphosting.api.ApiProxy$FeatureNotEnabledException: The Socket API will be enabled for this application once billing has been enabled in the admin console.

java.lang.Thread.getStackTrace(Thread.java:1568)
com.google.apphosting.runtime.ApiProxyImpl.doSyncCall(ApiProxyImpl.java:253)
com.google.apphosting.runtime.ApiProxyImpl.access$000(ApiProxyImpl.java:64)
com.google.apphosting.runtime.ApiProxyImpl$1.run(ApiProxyImpl.java:196)
com.google.apphosting.runtime.ApiProxyImpl$1.run(ApiProxyImpl.java:193)
java.security.AccessController.doPrivileged(Native Method)
com.google.apphosting.runtime.ApiProxyImpl.makeSyncCall(ApiProxyImpl.java:193)
com.google.apphosting.runtime.ApiProxyImpl.makeSyncCall(ApiProxyImpl.java:64)
com.google.apphosting.api.ApiProxy.makeSyncCall(ApiProxy.java:107)
com.google.apphosting.api.ApiProxy.makeSyncCall(ApiProxy.java:56)
com.google.appengine.api.socket.SocketApiHelper.apiProxyMakeSyncCall(SocketApiHelper.java:90)
com.google.appengine.api.socket.SocketApiHelper.makeSyncCall(SocketApiHelper.java:58)
com.google.appengine.api.socket.NameServiceImpl.lookupAllHostAddr(NameServiceImpl.java:61)
com.google.apphosting.util.ResolverManager$AppEngineNameservice.lookupAllHostAddr(ResolverManager.java:42)
java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1388)
java.net.InetAddress.getAllByName0(InetAddress.java:1341)
java.net.InetAddress.getAllByName(InetAddress.java:1255)
java.net.InetAddress.getAllByName(InetAddress.java:1186)
org.apache.http.impl.conn.DefaultClientConnectionOperator.resolveHostname(DefaultClientConnectionOperator.java:242)
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:130)
org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:150)
org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:575)
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:776)
dispatch.classic.BlockingHttp$class.dispatch$classic$BlockingHttp$$execute(Http.scala:45)
dispatch.classic.BlockingHttp$$anonfun$execute$1$$anonfun$apply$3.apply(Http.scala:58)
dispatch.classic.BlockingHttp$$anonfun$execute$1$$anonfun$apply$3.apply(Http.scala:58)
scala.Option.getOrElse(Option.scala:120)
dispatch.classic.BlockingHttp$$anonfun$execute$1.apply(Http.scala:58)
dispatch.classic.Http.pack(Http.scala:25)
dispatch.classic.BlockingHttp$class.execute(Http.scala:53)
dispatch.classic.Http.execute(Http.scala:21)
dispatch.classic.HttpExecutor$class.x(executor.scala:36)
dispatch.classic.Http.x(Http.scala:21)
dispatch.classic.HttpExecutor$class.when(executor.scala:50)
dispatch.classic.Http.when(Http.scala:21)
dispatch.classic.HttpExecutor$class.apply(executor.scala:60)
dispatch.classic.Http.apply(Http.scala:21)

これも結局dispatchが内部で依存してるApacheのhttp clientが、GAE上で使用禁止のsocketのAPIを使っていてだめらしい。(金払えとかいうエラーメッセージぇ・・・)

使い方変えれば回避できるのかもしれない?が、面倒なので調べてないdispatchはそのためのGAEのモジュールありますね https://github.com/dispatch/dispatch/blob/0.8.9/project/build.scala#L80-L86

で、流石にscala.io.Sourceは使いたくないし、そもそもの目的は、GAE上からgithubAPI呼び出したかったのだが

など、色々とハマった。疲れた