GraphQLをさわってみた

# GraphQLとは何か
API（クライアントとサーバ間）用のクエリ言語の一つである。（例：REST APIなど）

[公式ページ](http://graphql.org/)

**メリット：**

- 特別な環境に縛られることなく、様々プログラミング言語に対してライブラリが提供されている。
- クエリの形はレスポンスのJsonの構造と同じであるため、直感的でわかりやすい。
- サーバ側ではなく、クライアント側でどのようにレスポンスを返すかをクエリに定義することによって、決めることができる。
- ↑のメリットにより、本来何回もリクエストしなくてはならないものが一回のリクエストで実現することができる。　

# 実際にGraphQLを見てみよう。
前提：様々なプログラミング用のライブラリが提供されているが、今回はMacでgolangで進みます。

1. golang用のgraphQLのライブラリをローカルに取得する。([こちら](http://graphql.org/code/)より各言語用のライブラリを取得します。今回はgolangを使います。)
2. ターミナルより「go get github.com/graphql-go/graphql」でライブラリをインストールします。
3. ライブラリにあるサンプルを見てみよう。

```golang:main.go
package main

import (
   "encoding/json"
   "fmt"
   "io/ioutil"
   "net/http"

   "github.com/graphql-go/graphql" //ライブラリをインポート
)

// 構造体の定義
type user struct {
   ID   string `json:"id"`
   Name string `json:"name"`
}

// JSONデータ格納用
var data map[string]user

// レスポンスのタイプを定義する
var userType = graphql.NewObject(
   graphql.ObjectConfig{
      Name: "User",
      Fields: graphql.Fields{
         "id": &graphql.Field{
            Type: graphql.String,
         },
         "name": &graphql.Field{
            Type: graphql.String,
         },
      },
   },
)

// クエリの定義
var queryType = graphql.NewObject(
   graphql.ObjectConfig{
      Name: "Query",
      Fields: graphql.Fields{
         "user": &graphql.Field{
            Type: userType,
            Args: graphql.FieldConfigArgument{
               "id": &graphql.ArgumentConfig{
                  Type: graphql.String,
               },
            },
            Resolve: func(p graphql.ResolveParams) (interface{}, error) {
               idQuery, isOK := p.Args["id"].(string)
               if isOK {
                  return data[idQuery], nil
               }
               return nil, nil
            },
         },
      },
   })

var schema, _ = graphql.NewSchema(
   graphql.SchemaConfig{
      Query: queryType,
   },
)

// graphqlでリクエストされた時に実行される。
func executeQuery(query string, schema graphql.Schema) *graphql.Result {
   result := graphql.Do(graphql.Params{
      Schema:        schema,
      RequestString: query,
   })
   if len(result.Errors) > 0 {
      fmt.Printf("wrong result, unexpected errors: %v", result.Errors)
   }
   return result
}

func main() {
　　//data.jsonを取り込む
   _ = importJSONDataFromFile("data.json", &data)
　　
　　//ハンドラを登録
   http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
      result := executeQuery(r.URL.Query().Get("query"), schema)
      json.NewEncoder(w).Encode(result)
   })

   fmt.Println("Now server is running on port 8080")
   fmt.Println("Test with Get      : curl -g 'http://localhost:8080/graphql?query={user(id:\"1\"){name}}'")
   http.ListenAndServe(":8080", nil)
}

//data.jsonをmap型変数のdataに代入
func importJSONDataFromFile(fileName string, result interface{}) (isOK bool) {
   isOK = true
   content, err := ioutil.ReadFile(fileName)
   if err != nil {
      fmt.Print("Error:", err)
      isOK = false
   }
   err = json.Unmarshal(content, result)
   if err != nil {
      isOK = false
      fmt.Print("Error:", err)
   }
   return
}
```

## 実行結果
go.mainを実行し、下記のURLをたたく。
[http://localhost:8080/graphql?query={user(id:"1"){name}}](http://localhost:8080/graphql?query={user(id:"1"){name}})


<img width="609" alt="スクリーンショット 2018-04-20 17.18.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/250967/8d354545-8286-66ef-e93d-3d9cb5a70638.png">


## 元のデータ

```json:data.json
{
  "1": {
    "id": "1",
    "name": "Dan"
  },
  "2": {
    "id": "2",
    "name": "Lee"
  },
  "3": {
    "id": "3",
    "name": "Nick"
  }
}
```

## 結果
**元のデータより、user ID が1のuser nameを取得しています。**