見出し画像

#97 GraphQL

 先日OSCPを取得して、完全に満足しちゃっていましたが、OSCP受講のおまけでついてきた無線通信のコース(OSWP)も、せっかくなのでやってみました。
 昨日受験して、先ほど、合格通知がきました!内容はそれほど難しくなく、教材の内容を理解していれば簡単に解ける問題でしたが、OSCP同様、監視されながらの試験だったので緊張しました。

 さて、流行りかわかりませんが、GraphQLに触れる機会が増えてきました。FacebookのAPIで使われているので存在は知っていましたが、開発側の立場で扱うチャンスはそれほどありません。
 というわけで、Hello Worldまでやってみます。Expressでリクエストを受け取って、GraphQLにクエリを流し、結果をレスポンスとして返すような形にしたいと思います。

作業

ソースはGitHubで公開していますので、ご活用ください。


環境構築

GitHubからソースコードをクローンしたら、Dockerコンテナを立ち上げます。

docker compose up -d --build

http://localhost:3000にアクセスして、”Hello World!”と表示されればOKです。

GraphQL

GraphQL.jsを使用します。

app.jsの実装は以下の通りです。

var { graphql, buildSchema } = require("graphql")
const express = require('express')
const app = express()
const port = 3000
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

var schema = buildSchema(`
  type Query {
    hello: String
  }
`)

var rootValue = { hello: () => "Hello GraphQL!" }

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.post('/graphql', async (req, res) => {
  var source = req.body.query;
  var result = await graphql({ schema, source, rootValue });
  res.send(result);
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

/graphqlにPOSTでクエリを送ると、GraphQLから結果が返されます。curlで送信してみます。

$ curl -X POST http://localhost:3000/graphql -H "Content-type: application/json" -d '{"query": "{ hello }"}'
{"data":{"hello":"Hello GraphQL!"}}

期待通りです!

ちなみに、GraphQLには、Introspectionという機能があって、以下のようなクエリでスキーマの情報を取得することができます。

{__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}

そのままでは読みにくいですが、スキーマの定義が返ってきます。

{"data":{"__schema":{"types":[{"name":"Query","fields":[{"name":"hello","args":[]}]},{"name":"String","fields":null},{"name":"Boolean","fields":null},{"name":"__Schema","fields":[{"name":"description","args":[]},{"name":"types","args":[]},{"name":"queryType","args":[]},{"name":"mutationType","args":[]},{"name":"subscriptionType","args":[]},{"name":"directives","args":[]}]},{"name":"__Type","fields":[{"name":"kind","args":[]},{"name":"name","args":[]},{"name":"description","args":[]},{"name":"specifiedByURL","args":[]},{"name":"fields","args":[{"name":"includeDeprecated","description":null,"type":{"name":"Boolean","kind":"SCALAR","ofType":null}}]},{"name":"interfaces","args":[]},{"name":"possibleTypes","args":[]},{"name":"enumValues","args":[{"name":"includeDeprecated","description":null,"type":{"name":"Boolean","kind":"SCALAR","ofType":null}}]},{"name":"inputFields","args":[{"name":"includeDeprecated","description":null,"type":{"name":"Boolean","kind":"SCALAR","ofType":null}}]},{"name":"ofType","args":[]}]},{"name":"__TypeKind","fields":null},{"name":"__Field","fields":[{"name":"name","args":[]},{"name":"description","args":[]},{"name":"args","args":[{"name":"includeDeprecated","description":null,"type":{"name":"Boolean","kind":"SCALAR","ofType":null}}]},{"name":"type","args":[]},{"name":"isDeprecated","args":[]},{"name":"deprecationReason","args":[]}]},{"name":"__InputValue","fields":[{"name":"name","args":[]},{"name":"description","args":[]},{"name":"type","args":[]},{"name":"defaultValue","args":[]},{"name":"isDeprecated","args":[]},{"name":"deprecationReason","args":[]}]},{"name":"__EnumValue","fields":[{"name":"name","args":[]},{"name":"description","args":[]},{"name":"isDeprecated","args":[]},{"name":"deprecationReason","args":[]}]},{"name":"__Directive","fields":[{"name":"name","args":[]},{"name":"description","args":[]},{"name":"isRepeatable","args":[]},{"name":"locations","args":[]},{"name":"args","args":[{"name":"includeDeprecated","description":null,"type":{"name":"Boolean","kind":"SCALAR","ofType":null}}]}]},{"name":"__DirectiveLocation","fields":null}]}}}

開発者にはありがたい一方、余計な情報まで公開してしまいそうで怖いです。今回使用しているGraphQL.jsには標準ではIntrospectionを無効にする機能はないようで、別途パッケージをインストールする必要があるみたいです。

まとめ

 GraphQLクエリを実行するところまでは結構あっさりできました。ただ、実運用するには、スキーマの定義やデータベースとのつなぎ合わせなどが必要です。データベースにはNeo4jのようなグラフDBを使うのが筋なのでしょうか?Postgresで構築する記事なども発見しました。
まだまだ奥が深そうです…

EOF

この記事が気に入ったらサポートをしてみませんか?