JSUG勉強会 2021年その2 Spring GraphQLをとことん語る夕べでの発表のスライドとコード例です。 発表時はSpring GraphQL 1.0.0-M1でしたがM2、M3とバージョンを重ねているためたまにスライドを更新しています。 JSUGでの発表当時のスライドは20210806-jsugタグを参照してください。
PlantUMLで描いた図をビルドする。
java -jar ~/plantuml.jar -tsvg docs/plantuml.puスライドをビルドする。
npx @marp-team/marp-cli@latest --html --output docs/index.html docs/slide.md/docsをGitHub Pagesでホスティングするように設定しているので次のURLでスライドが見られる。
./mvnw spring-boot:run
ブラウザで http://localhost:8080/graphiql を開く。
スライドにもあったクエリーを試す。
query {
article(id: 1) {
id
title
content
category {
id
name
}
}
}タイトルだけ取得するようにしてみる。
query {
article(id: 1) {
title
}
}変数を使ってみる。
query GetArticle($id: ID!) {
article(id: $id) {
title
}
}{
"id": 1
}curlでも試してみる。
curl -s http://localhost:8080/graphql -H "Content-Type: application/json" -d '{"query": "{article(id: 1) { id, title, content, category { id, name } }}"}' | jq
subscription操作も試してみる。
subscription {
count
}結果のエリアにカウントアップされて1から10まで表示される。
wscatでも確認してみる。
wscatはnpm install -g wscatでインストールできる。
wscat --connect ws://localhost:8080/graphql
subscriptionのプロトコルはまだ理解していないので、Spring GraphQLのコードを読んでわかった手順を実施する。
まずはconnection_initが必要。
{"type": "connection_init"}
それからsubscribe。
待っていると1秒おきにカウントアップする値が返される。
{"type": "subscribe", "id": "...", "payload": {"query": "subscription { count }"}}
もちろん変数も使える。
{"type": "subscribe", "id": "...", "payload": {"query": "subscription Count($size: Int!) { count(size: $size) }", "variables": {"size": 5 }}}
まずはN + 1。
query {
comics {
title
publisher {
name
}
}
}Fetch Query.comics以降のログを見るとcomicsで1回、comics.publisherで10回のクエリーが発行されていることがわかる。
次にDataLoader版。
query {
comics {
title
author {
name
}
}
}Fetch Query.comics以降のログを見るとcomicsとcomics.authorが共に1回ずつのクエリー発行で済んでいることがわかる。
まずはafterを指定せずクエリーーを発行して返ってくる値を確認する。
query GitCommits {
history {
forward(first: 3) {
edges {
node {
hash
message
}
cursor
}
pageInfo {
hasPreviousPage
hasNextPage
startCursor
endCursor
}
}
}
}それからpageInfoの値を見ながらafterを設定しつつクエリーを試す。
query GitCommits {
history {
forward(first: 3, after: "3") {
edges {
node {
hash
message
}
cursor
}
pageInfo {
hasPreviousPage
hasNextPage
startCursor
endCursor
}
}
}
}後方も試す。
query GitCommits {
history {
backward(last: 3, before: "7") {
edges {
node {
hash
message
}
cursor
}
pageInfo {
hasPreviousPage
hasNextPage
startCursor
endCursor
}
}
}
}次のクエリーを実行するとエラー(Unauthorized)になる。
{
security {
protected
}
}REQUEST HEADERSという場所に次のJSONを書いて実行するとエラーにならず値が返ってくる。
{
"Authorization": "Basic ZGVtbzpzZWNyZXQ="
}これは該当のDataFetcher内で呼び出されているコンポーネントのメソッドに@PreAuthorize("isAuthenticated()")を付けている。
カスタムdirectiveで認証を表現した例も作ってみた。
次のクエリーが@authenticatedというカスタムdirectiveで保護したフィールドへのアクセスとなる。
{
security {
protected2
}
}Authorizationヘッダーの有無による違いを試してみてほしい。
curl -s localhost:8080/actuator/metrics/graphql.request | jq
curl -s localhost:8080/actuator/metrics/graphql.datafetcher | jq
curl -s localhost:8080/actuator/metrics/graphql.error | jq
graphqlvizを使うとGraphQLスキーマを図にできる。
npx graphqlviz http://localhost:8080/graphql | dot -Tpng -o graphql-schema.png
次のような図が生成される。
スライド(docs/配下にあるファイル)はCC BY 4.0、ソースコード(スライド以外のファイル)はMITを適用します。
