# HOW TO GRAPHQLでGraphQLの勉強をはじめました その③

# Getting Started

プロジェクトとGraphQLサーバーのセットアップをして、はじめてのGraphQLクエリを実装していきます。

# Creating the project

Yarnを使ってやっていくそうです。

$ mkdir hackernews-node
$ cd hackernews-node/
$ yarn init -y
yarn init v1.19.1
warning The yes flag has been set. This will automatically answer yes to all questions, which may have security implications.
warning ../package.json: No license field
success Saved package.json
✨  Done in 0.03s.

# Creating a raw GraphQL server

srcディレクトリを作ってindex.jsファイルを配置します。

mkdir src
touch src/index.js

graphql-yogaを入れていきます。 👇はブワっと長いですがExpress.jsをベースにproduction-readyなGraphQLサーバーということで。機能的には色々あるけどTypeScriptで動くとかGraphQL Playgroundがout-of-the-boxで使えるとか、Expressのミドルウェアを柄できるとか、Queryのパフォーマンスをトレース出来るとか、AWS LambdaとかHerokuとかでも動かせる多機能なものなのだそうです。

$ yarn add graphql-yoga
yarn add v1.19.1
warning ../package.json: No license field
info No lockfile found.
[1/4] 🔍  Resolving packages...
warning graphql-yoga > @types/graphql@14.5.0: This is a stub types definition. graphql provides its own type definitions, so you do not need this installed.
warning graphql-yoga > apollo-upload-server@7.1.0: Please migrate to https://npm.im/graphql-upload (see https://git.io/fADhl).
warning graphql-yoga > apollo-server-express > apollo-server-core > graphql-extensions > core-js@2.6.11: core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning "graphql-yoga > graphql-playground-middleware-lambda@1.7.12" has unmet peer dependency "aws-lambda@^0.1.2".
warning "graphql-yoga > graphql-subscriptions@0.5.8" has incorrect peer dependency "graphql@^0.10.5 || ^0.11.3 || ^0.12.0 || ^0.13.0".
warning "graphql-yoga > apollo-server-express > apollo-server-core@1.4.0" has incorrect peer dependency "graphql@^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0".
warning "graphql-yoga > apollo-server-express > apollo-server-core > apollo-cache-control@0.1.1" has incorrect peer dependency "graphql@0.10.x - 0.13.x".
warning "graphql-yoga > apollo-server-express > apollo-server-core > apollo-tracing@0.1.4" has incorrect peer dependency "graphql@0.10.x - 0.13.x".
warning "graphql-yoga > apollo-server-express > apollo-server-core > graphql-extensions@0.0.10" has incorrect peer dependency "graphql@0.10.x - 0.13.x".
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
warning Your current version of Yarn is out of date. The latest version is "1.22.0", while you're on "1.19.1".
info To upgrade, run the following command:
$ brew upgrade yarn
success Saved 89 new dependencies.
info Direct dependencies
└─ graphql-yoga@1.18.3
info All dependencies
├─ @types/aws-lambda@8.10.13
├─ @types/body-parser@1.19.0
├─ @types/connect@3.4.33
├─ @types/cors@2.8.6
├─ @types/express@4.17.2
├─ @types/graphql-deduplicator@2.0.0
├─ @types/graphql@14.5.0
├─ @types/mime@2.0.1
├─ @types/range-parser@1.2.3
├─ @types/serve-static@1.13.3
├─ @types/zen-observable@0.5.4
├─ @wry/equality@0.1.9
├─ accepts@1.3.7
├─ apollo-cache-control@0.1.1
├─ apollo-link@1.2.13
├─ apollo-server-core@1.4.0
├─ apollo-server-express@1.4.0
├─ apollo-server-lambda@1.3.6
├─ apollo-server-module-graphiql@1.4.0
├─ apollo-tracing@0.1.4
├─ apollo-upload-server@7.1.0
├─ apollo-utilities@1.3.3
├─ array-flatten@1.1.1
├─ async-limiter@1.0.1
├─ backo2@1.0.2
├─ body-parser-graphql@1.1.0
├─ body-parser@1.19.0
├─ buffer-from@1.1.1
├─ busboy@0.2.14
├─ content-disposition@0.5.3
├─ cookie-signature@1.0.6
├─ cookie@0.4.0
├─ core-js@2.6.11
├─ core-util-is@1.0.2
├─ cors@2.8.5
├─ deprecated-decorator@0.1.6
├─ destroy@1.0.4
├─ dicer@0.2.5
├─ ee-first@1.1.1
├─ eventemitter3@3.1.2
├─ express@4.17.1
├─ fast-json-stable-stringify@2.1.0
├─ finalhandler@1.1.2
├─ forwarded@0.1.2
├─ fs-capacitor@1.0.1
├─ graphql-deduplicator@2.0.5
├─ graphql-extensions@0.0.10
├─ graphql-import@0.7.1
├─ graphql-middleware@4.0.1
├─ graphql-playground-middleware-express@1.7.11
├─ graphql-playground-middleware-lambda@1.7.12
├─ graphql-subscriptions@0.5.8
├─ graphql-tools@4.0.7
├─ graphql-upload@8.1.0
├─ graphql-yoga@1.18.3
├─ graphql@14.6.0
├─ http-errors@1.7.3
├─ inherits@2.0.4
├─ ipaddr.js@1.9.1
├─ isarray@0.0.1
├─ iterall@1.3.0
├─ lodash@4.17.15
├─ media-typer@0.3.0
├─ merge-descriptors@1.0.1
├─ methods@1.1.2
├─ mime-db@1.43.0
├─ mime@1.6.0
├─ ms@2.0.0
├─ negotiator@0.6.2
├─ object-assign@4.1.1
├─ path-to-regexp@0.1.7
├─ proxy-addr@2.0.6
├─ raw-body@2.4.0
├─ resolve-from@4.0.0
├─ safer-buffer@2.1.2
├─ serve-static@1.14.1
├─ source-map-support@0.5.16
├─ source-map@0.6.1
├─ string_decoder@0.10.31
├─ subscriptions-transport-ws@0.9.16
├─ symbol-observable@1.2.0
├─ type-is@1.6.18
├─ unpipe@1.0.0
├─ utils-merge@1.0.1
├─ uuid@3.4.0
├─ vary@1.1.2
├─ ws@5.2.2
├─ zen-observable-ts@0.8.20
└─ zen-observable@0.8.15
✨  Done in 3.42s.

そして、いよいよコードを書いていきます!(ここはコピペせずに頑張ってタイプしていきます!)

const { GraphQLServer} = require('graphql-yoga')

const typeDefs = `
type Query {
  info: String!
}
`

const resolvers = {
  Query: {
    infor: () => `This is the API of a Hackernews Clone`
  }
}

const server = new GraphQLServer({
  typeDefs,
  resolvers,
})

server.start(() => console.log(`Server is runnning on http://localhost:4000`))

typeDefsでGraphQLスキーマを定義して(シンプルなクエリ。フィールドは文字列型のinfoでnullは許可しない)、resolversでQuery.infoされた時に動く実装をして、それがserverで動きますよ、と。

ということで、いよいよサーバーをGraphQL Serverを起動していきます。

node src/index.js

localhost:4000にアクセスすると👇なんかカッコよくないですか?っていう。パワフルなGraphQL IDEということ。

server

DOCSタブを押下すると、自動生成されたドキュメントが見れます。

server

ってことで、GraphQLクエリを叩いてみます。CMD+Enterで叩ける、とのこと。

query {
  info
}

キターーーッ!

query

ということで、いわゆるGraphQLにおけるHello World的なところまでこれた気がします。

んじゃ、String!なところにnullを返したらどうなるの?と。 ということでリゾルバを👇のようにしてからGraphQLサーバーを再起動します、と。

const resolvers = {
  Query: {
    info: () => null
  }
}

で、クエリを実行すると👇のようなエラーが返ってきて

{
  "data": null,
  "errors": [
    {
      "message": "Cannot return null for non-nullable field Query.info.",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "info"
      ]
    }
  ]
}

サーバーも👇のようなエラーを吐いていました。

$ node src/index.js 
Server is runnning on http://localhost:4000
Error: Cannot return null for non-nullable field Query.info.
    at completeValue (/Users/eijishinohara/hackernews-node/node_modules/graphql/execution/execute.js:560:13)
    at completeValueCatchingError (/Users/eijishinohara/hackernews-node/node_modules/graphql/execution/execute.js:495:19)
    at resolveField (/Users/eijishinohara/hackernews-node/node_modules/graphql/execution/execute.js:435:10)
    at executeFields (/Users/eijishinohara/hackernews-node/node_modules/graphql/execution/execute.js:275:18)
    at executeOperation (/Users/eijishinohara/hackernews-node/node_modules/graphql/execution/execute.js:219:122)
    at executeImpl (/Users/eijishinohara/hackernews-node/node_modules/graphql/execution/execute.js:104:14)
    at Object.execute (/Users/eijishinohara/hackernews-node/node_modules/graphql/execution/execute.js:64:63)
    at doRunQuery (/Users/eijishinohara/hackernews-node/node_modules/apollo-server-core/dist/runQuery.js:124:42)
    at /Users/eijishinohara/hackernews-node/node_modules/apollo-server-core/dist/runQuery.js:21:56
    at processTicksAndRejections (internal/process/task_queues.js:93:5)

んま、こういうちゃんとしたスキーマ定義があることで、要らんミスに時間取られたりしないしイイよね、と。

# Creating a raw GraphQL server

続いて実践的な感じに移ります。 👇Queryにusersとuser、MutationにcreateUser。これをするにはUser typeが必要に。

type Query {
  users: [User!]!
  user(id: ID!): User
}

type Mutation {
  createUser(name: String!): User!
}

type User {
  id: ID!
  name: String!
}

上記のinfoで使ったStringはスカラ値でしたが、Userのようなオブジェクトの取り扱いはどうするのか?っていう話。

想定されるオペレーションは👇のような感じ。

# Query for all users
query {
  users {
    id
    name
  }
}

# Query a single user by their id
query {
  user(id: "user-1") {
    id
    name
  }
}

# Create a new user
mutation {
  createUser(name: "Bob") {
    id
    name
  }
}
  • idとnameでクエリを行いUserが返ってくる
  • Userにまつわるアレやコレや👇
    • [User!]の意味はnullではないUserオブジェクトの配列
    • user(id: ID!)はUserが返ってくる。nullの場合もありえる
    • createUser(name:String!)はUser!が返ってくる(nullではないUser)

これをPrismaに食わせるとDBアクセスとかゴニョゴニョしてくれる、とのことですが、セオリーについてはこんなところにしておいて、次の章では引き続きコードを書いていきましょう的な。

このエントリーをはてなブックマークに追加

Algolia検索からの流入のみConversionボタン表示