Lagomのサービスから別のサービスを呼び出してみる

Lagomを試してみるシリーズ第7回です。今回はサービスから別サービスの呼び出しを試してみました。少しずつリアクティブっぽい感じになってきましたね。

別のサービスを呼び出すのは簡単で、以下のようにサービスのインターフェースをDIするだけで呼び出すことができます。呼び出した結果に対して処理を行う場合はthenApplyなどで次の処理を合成します。ScalaFutureを扱ったことがある方であれば、Futureに対するmapみたいなものだと思えばよいかと思います。CompletionStageにはこの他にも合成用の様々なメソッドが用意されています。

public class MyServiceImpl implements MyService {

  private final HelloService helloService;

  @Inject
  public MyServiceImpl(HelloService helloService){
    this.helloService = helloService;
  }

  @Override
  public ServiceCall<NotUsed, NotUsed, String> hoge() {
    return (id, msg) -> {
      CompletionStage<HelloResponse> f = helloService.hello().invoke(HelloRequest.of("Japan", "Naoki"));
      return f.thenApply(res -> res.message() + "!");
    };
  }
}

クライアントのインターフェースをDIするだけでサービスを呼び出せるということはバイトコード生成的なことをやってるんだろうと思ったらjava.lang.reflect.Proxyが使われているようです。

github.com

他のサーバで動いているサービスの呼び出しはどうやればいいんだろう?このあたりはLagomの肝の1つだと思うので、もっと複雑なケースや背後の仕組みも含めてもう少し詳しく調べてみたいところです。

また、Lagomのドキュメントによると、別サービスを呼び出すのではなく、以下のようにServiceCall自体を合成することもできるみたいです。

public <Id, Request, Response> ServerServiceCall<Id, Request, Response> logged(
    ServerServiceCall<Id, Request, Response> serviceCall) {
  return HeaderServiceCall.compose(requestHeader -> {
    System.out.println("Received " + requestHeader.method() + " " + requestHeader.uri());
    return serviceCall;
  });
}

public ServerServiceCall<NotUsed, String, String> sayHello() {
  return logged(
      (id, name) -> completedFuture("Hello " + name)
  );
}

認証やログなどの共通的な処理はこんな感じで実装するとよさそうです。