GraphQL Advent Calendar 2018 の18日目です。
最近、GraphQL を試しに触り始めてみたという程度です。普段は Java や Spring を使っています。というわけで、今回は Spring Boot で試してみたときの備忘録シリーズの第3弾となります。第1弾と第2弾はこちら。Query と Mutation を試してみたときの備忘録です。が、本当に触ってみた程度の内容です...。
今回は Subscription を試してみます。相変わらず触ってみた程度の内容ですが、サンプルコードはこちら。
kntmr/playground/graphql-spring-examples - GitHub
以下、備忘録。
依存ライブラリ
Subscription の Resolver からは Publisher<T>
を返す。取り急ぎ、Spring WebFlux を追加。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
schema / データクラス
スキーマに Subscription の IF を定義。
// ... (略) type Subscription { added(id: ID!): ToDo }
Resolver
Subscription の場合は、GraphQLSubscriptionResolver
インタフェースを実装する。今回は EmitterProcessor<T>
で Publisher<T>
を返すことに。また、引数で指定された ID で filter することで、Subscribe したユーザーごとに Subscription を返すようにする。
@Component public class TodoSubscriptionResolver implements GraphQLSubscriptionResolver { private TodoEmitterProcessor processor; public TodoSubscriptionResolver(TodoEmitterProcessor processor) { this.processor = processor; } public Publisher<ToDo> added(int id) { return processor.getProcessor().filter(todo -> todo.getUserId() == id); } }
EmitterProcessor<T>
を持つクラス。
@Component public class TodoEmitterProcessor { private EmitterProcessor<ToDo> processor; public TodoEmitterProcessor() { processor = EmitterProcessor.create(); } public EmitterProcessor<ToDo> getProcessor() { return processor; } public void sendMessage(ToDo todo) { processor.onNext(todo); } }
Mutation で更新するときに EmitterProcessor#onNext
する。
// ... (略) ToDo newTodo = new ToDo( ... ); todoDao.add(newTodo); processor.sendMessage(newTodo); // 追加
リクエスト / Subscription
アプリを起動するとコンソールに以下のログが出力されている。
Registering ServerEndpointConfig: ServerEndpointRegistration for path '/subscriptions': class graphql.servlet.GraphQLWebsocketServlet
というわけで、今回は GraphiQL ではなく、WebSocket で /subscriptions
にリクエストする。
const ws = new WebSocket('ws://localhost:8080/subscriptions') ws.onopen = (e) => { console.log('ws opened.') ws.send(JSON.stringify({ query: `subscription { added(id: 1) { // ★ id, content, completed } }` })); } ws.onmessage = (e) => { console.log('ws message.') var resp = JSON.parse(e.data); // ... (略) } ws.onclose = (e) => { console.log('ws closed.') ws.close(); } ws.onerror = (e) => { console.log('error!!') ws.close(); }
GraphiQL などから Mutation でデータを更新すると、ws.onmessage
でイベントが通知される。Resolver 側で ID で filter しているので、他ユーザーのデータを Mutation に投げた場合はイベントは通知されない。
所感
まだまだあやしいところはありますが、ここまでで Query / Mutation / Subscription の3機能をざっくり試してみました。今後はもう少し実践的な内容を調べていきたいと思います。特に、自動生成などの開発ツール周りを調べたい。
とりあえず、以下のドキュメントをもっと読み込んでみようかと。
その他
先日の JJUG CCC 2018 Fall で GraphQL のセッションがありました。
www.slideshare.net
デモのリポジトリはこちら。