{
posts {
title,
summary,
created
}
}
{
"data": {
"posts": [
{
"title": "new blog post",
"summary": "this is new post",
"created": "2017-3-13 20:12:03"
},
{
"title": "second post",
"summary": "this is second post",
"created": "2017-3-14 13:22:35"
},
{...},
{...}
]
}
}
Query
Result
{
posts {
title,
summary,
created,
author {
name,
mail
}
}
}
{
"data": {
"posts": [
{
"title": "new blog post",
"summary": "this is new post",
"created": "2017-3-13 20:12:03",
"author": {
"name": "ben",
"mail": "ben@blogger.com"
}
},
{
"title": "second post",
"summary": "this is second post",
"created": "2017-3-14 13:22:35",
"author": {
"name": "chris",
"mail": "chris@blogger.com"
}
}
]
}
}
Query
Result
{
posts(count: 1) {
title,
summary,
created
}
}
{
"data": {
"posts": [
{
"title": "new blog post",
"summary": "this is new post",
"created": "2017-3-13 20:12:03"
}
]
}
}
Query
Result
{
posts(count: 1) {
title,
summary,
created(format: DATE)
}
}
{
"data": {
"posts": [
{
"title": "new blog post",
"summary": "this is new post",
"created": "2017/3/13"
}
]
}
}
Query
Result
{
posts {
title
},
authorNames: authors {
name
},
authorMails: authors {
mail
}
}
{
"data": {
"posts": [
{"title": "new blog post"},
{"title": "second post"}
],
"authorNames": [
{"name": "ben"},
{"name": "chris"}
],
"authorMails": [
{"mail": "ben@blogger.com"},
{"mail": "chris@blogger.com"}
],
}
}
Query
Result
{
jan: posts(month: 1) {
...blogData
},
feb: posts(month: 2) {
...blogData
},
mar: posts(month: 3) {
...blogData
}
}
fragment blogData on Posts {
title,
body,
author {
name
}
}
{
"data": {
"jan": [{
"title": "January post",
"body: "...",
"author": {
"name": "ben"
}
}],
"feb": [{
"title": "February post",
"body: "...",
"author": {
"name": "chris"
}
}],
"mar": [{
"title": "March post",
"body: "...",
"author": {
"name": "ben"
}
}],
}
}
Query
Result
queryを使って関数のようなものを定義
引数として$を接頭辞にした引数(と、その型)を定義
queryの中にある$xxxへ引数が渡される。
variablesはキーバリュー型となる
query getPosts($count: Int!){
posts(count: $count) {
title,
summary,
created
}
}
{
"data": {
"posts": [
{
"title": "new blog post",
"summary": "this is new post",
"created": "2017-3-13 20:12:03"
},
{...},
{...}
]
}
}
Query
Result
Variables
{
"count": 3
}
getPosts の部分
query getPosts($count: Int!){
posts(count: $count) {
title,
summary,
created
}
}
Variablesなどを用いて、動的にクエリのFieldsを減らしたり、増やしたりする方法
@include(if: Boolean) でifがtrueのときフィールドを追加
@skip(if: Boolean) ifがtrueのときフィールドを除去
query getPosts($noSummary: Boolean){
posts {
title,
summary @skip(if: $noSummary),
created
}
}
query getComment {
comments {
name,
comment,
... on FacebookUser {
realName
}
... on TwitterUser {
account
}
}
}
{
"data": {
"comments": [
{
"name": "Brett",
"comment": "...",
"realName": "Brett Reed"
},
{
"name": "Matt",
"comment": "...",
"account": "@matt"
}
]
}
}
Query
Result
mutation {
createAuthor(
name: "tim",
mail: "tim@blogger.com"
) {
_id
name
}
}
{
"data": {
"createAuthor": {
"_id": "tim",
"name": "tim"
}
}
}
Query
Result
mutation {
"tim": createAuthor(
name: "tim",
mail: "tim@blogger.com"
) {
_id
}
"fred": createAuthor(
name: "fred",
mail: "fred@blogger.com"
) {
_id
}
}
{
"data": {
"tim": {
"_id": "tim"
}
"fred": {
"_id": "fred"
}
}
}
Query
Result
type Post {
title: String!
summary: String
body: String
created: String
author: Author
}
Scheme
実際のSchemaの定義
Postは GraphQL Object Typeでいわれるオブジェクト型、幾つかのフィールドを持つことができる。
title, summary, body, created, author はフィールド
StringはGraphQLで定義できる、スカラー型のひとつ。!をつけることでnon-nullableであることを示す
[Episode]は Episode型の配列であることを定義。上記同様に!はnon-nullableを示す。ただこの場合は0個またはそれ以上の配列となる
type BlogSchema {
posts(count: Int! = 10): [Post]
}
Scheme
{
type Query {
...
}
type Mutation {
...
}
}
scalar Date
enum Category {
JAVA
JAVASCRIPT
NODEJS
PYTHON
}
type Post {
title: String!
comments: [Comment]!
}
interface HasAuthor {
author: Author
}
type Comment implements HasAuthor {
comment: String
}
type Post implements HasAuthor {
title: String
body: String
}
インストール
$ npm i express graphql body-parser --save
// index.js
const express = require('express');
const app = express();
const PORT = 3000;
const server = app.listen(PORT, function () {
const host = server.address().address;
const port = server.address().port;
console.log('listening at http://%s:%s', host, port);
});
index.js
$ node index.js
const graphql = require('graphql');
const { GraphQLSchema, GraphQLObjectType, GraphQLString } = graphql;
const Query = new GraphQLObjectType({
name: 'baseSchema',
fields : {
ping: {
type: GraphQLString,
resolve: () => 'pong'
}
}
});
// const Mutation = new GraphQLObjectType({...});
const schema = new GraphQLSchema({
query: Query
//, mutation: Mutation
});
module.exports = schema;
schema.js
スキーマを定義
const graphql = require('graphql');
const bodyParser = require('body-parser');
const schema = require('./schema.js');
// POSTのbodyをtextとしてパース
app.use(bodyParser.text({ type: 'application/graphql' }));
app.post('/graphql', (req, res) => {
// GraphQLを実行
graphql.graphql(schema, req.body).then((result) => {
res.send(JSON.stringify(result, null, 2));
});
});
リクエストされたqueryを処理 (index.js)
$ curl -XPOST -H "Content-Type:application/graphql" \
-d "query baseSchema { ping }" http://localhost:3000/graphql
チェック
{
"data": {
"ping": "pong"
}
}
GraphQLのSchemaを可視化する+Sandboxとして利用できるReactのコンポーネント
GraphQL HTTP Server Middleware
expressでGraphQLを定義しやすくするミドルウェア
上記のGraphiQLを内包している
Just in Timeなデータを取得できる
クライアント側(UI側)の変更に対して、サーバ側でAPIを変えなくてもいい
クライアントが定義情報を知っているから、バージョン管理は(あんまり)しなくてもいい
APIドキュメントも自動生成できる
学習コスト(特にサーバ側の!)
どのくらいの規模に耐えうるか?(複雑なスキーマが発生してメンテナンス性が下がったりするか)
開発パラダイムのシフト(特にサーバ側の!)