皆さま、”GraphQL“ってご存知ですか?
正直に話すと、筆者は2021/7現在、『RESTとか聞いたことあるけど、それと何が違うの?(そもそもRESTも何かわからない)』レベルの知識しかありません🙄 つまり、何も知りません🙄
あるご縁でこの知識が必要になり、学習したことをアウトプットしようとこの記事を書くことにしました。
筆者も初めて学習するため、記事の内容のクオリティは少しずつ高くしていこうと思いますが、最初は覚え書き程度になると思いますので、暖かい気持ちで見守っていただければと思います◎
学習を進めるにあたり、次のサイトがかなり分かりやすく勉強になったので共有します
⇨https://eh-career.com/engineerhub/entry/2018/12/26/103000
それではさっそく初めていこう!
Contents
- 1 GraphQLの概要
- 1.1 GraphQLとは
- 1.2 GrapgQLのメリデメ
- 1.3 GraphQLとRESTの違い
- 1.4 GraphQLの処理フロー
- 1.5 クエリ(query), フィールド(Fields), 型(Types)
- 1.6 引数(Arguments)
- 1.7 エイリアス(Aliases)
- 1.8 フラグメント(Fragment)
- 1.9 操作名(Operation Name)
- 1.10 変数(Variables)
- 1.11 ミューテーション(Mutations)
- 1.12 インラインフラグメント(Inline Fragments)と型名(__typename)
- 1.13 型システム(Types System)、スカラー型(Scalar Types)、オブジェクト型(Object Types)、スキーマ(Schemas)
- 1.14 ページネーション(Pagination)
- 1.15 Apolloとは
GraphQLの概要
GraphQLとは
✅ Facebookが開発しているWebAPI(Web Application Programming Interface)のための規格
(API:ソフトウェアやアプリケーションの一部をプログラミングを介して第三者が開発したソフトウェアと機能を繋いで共有すること)
✅ DSL(Domain Specific Language):ドメイン固有言語であり、特定のタスク向けに開発された言語
⇨SQL, Dockerfile, yamlもその一つ
✅ フロントエンド(クライアント)側の『クエリ言語』とバックエンド側(DB)の『スキーマ言語』から構成される
✅ ある決まった定義に従ってクエリを書き、サーバーサイドと通信を取ることでJSON形式で受け取る
GrapgQLのメリデメ
メリット
✅ “Ask for what you nee, get exactly that“
⇨サーバーに対して必要なデータを必要なだけリクエストできる
✅ “Get many resources in a single request“
⇨一度のリクエストで関連するデータを全て得ることができる
✅ “Describe what’s possible with a type system“
⇨スキーマ言語で型やフィールドが定義されており、GraphQLは保障された型でリクエスト、レスポンスするため、高品質のコードが実現可能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// Request { hero{ name height mass } } //Response { "hero": { "name": "Luke Skywalker", "height": 172, "mass": 80 } } |
✅クエリがレスポンスデータの構造に似ていて情報が多い
⇨Web APIに対する知識が浅くてもGraphQLのクエリであれば理解が容易で読み書きできる
✅スキーマによる型付けにより型安全な運用ができる、レスポンスに含まれるデータ指定が必須
⇨生産性が高く、品質の良いクライアントコードが実現できる
✅ スキーマ情報を利用してクエリを書く際に、エディタにおける補完や型チェックなどの開発サポートツールが充実している
⇨クエリの学習コストが低い
デメリット
✅ APIのHTTPエンドポイントが一つだけのため、全データがまとめられているため、分析、パフォーマンス分析が困難
⇨ResufulAPIのように一つのURL(エンドポイント)に一つのAPIを対応させたWebAPIモデルと、現在の一つのURLに複数のAPIを対応させたAPM(Application Performance Management)想定のWebAPIモデルが異なる
⇨ツールの対応が追いついてないだけのため、ブロッカーというほどの問題でもない
✅ GraphQLのクライアントの実装はそこまで難しくないが、処理系の実装コストがかなり大きい
⇨実装がシンプルなResuful APIと比べて懸念点となる
✅ 画像や動画などの大容量バイナリの扱いが難しい
⇨データ授受のシリアライズ(一つの文字列やバイト列で並べる操作や処理のこと)方法は規定していないが多くのケースはJSONのため、バイナリのシリアライズを苦手ととする
GraphQLとRESTの違い
※このサイトが非常に分かりやすかったので引用しています
✅ REST: 静的 ↔︎ GraphQL: 動的
✅ クライアントからの複数のrequestに対してendpointが一つでDBへアクセスすることができ、シンプルな構造を持つ
✅標準化された言語で特別な仕様を持つことにより、クライアント側とサーバー側を強力に結びつけることが可能
⇨標準化され両デバイス間で認識できる言語のため、開発がスムーズに行える
GraphQLの処理フロー
✅まずは下記の流れをしっかり頭に入れる
- クエリ言語(query, mutation, subscription)でGraphQLに対してリクエストを送る
- リクエストされたクエリはGraphQL内で処理され、スキーマ言語で記述されたデータにアクセスする
- GraphQLはデータをJSONファイルに変換してクライアント側にレスポンスする
クエリ(query), フィールド(Fields), 型(Types)
✅ query: クライアントがサーバーからデータをリクエスト、取得する際に利用する操作(query)
✅ Field: クエリで操作できる、DBに存在するデータの最小単位(viewer, login)
✅ Types: フィールドで定義されたデータの種類(User, String)
1 2 3 4 5 6 |
// Request query { viewer { // viewer: User!→ viewerというフィールドはnon-nullなUser型のデータ login // login: String!→ loginは<meta charset="utf-8">non-nullなString型のデータ } } |
引数(Arguments)
✅ クエリでデータを取得するのに渡す値のこと
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// Request query { repository(owner: "facebook", name: "graphql") { // owner, nameが引数 description homepageUrl url } } // Response { "data": { "repository": { "description": "GraphQL is a query language and execution engine tied to any backend service.", "homepageUrl": "https://spec.graphql.org", "url": "https://github.com/graphql/graphql-spec" } } } |
エイリアス(Aliases)
✅ 同じフィールド(user)を並列で並べることはできない⇨エイリアスを付与することで解決する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// Request # query { # user(login: "skmkuma") { # bio # login # } # user(login: "skmkuma") { # bio # login # } # } query { user1: user(login: "skmkuma") { bio login } user2: user(login: "skmkuma") { bio login } } <meta charset="utf-8">// Response { "data": { "user1": { "bio": "AI/Mobile App development engineer|\r\nAI/ machine learning/Python/Django/ Flutter/Dart/Firebase/Docker/Jetson/Raspberry Pi\r\n", "login": "skmkuma" }, "user2": { "bio": "AI/Mobile App development engineer|\r\nAI/ machine learning/Python/Django/ Flutter/Dart/Firebase/Docker/Jetson/Raspberry Pi\r\n", "login": "skmkuma" } } } |
フラグメント(Fragment)
✅ 冗長なコードをひとまとめにするGraphQLの機能
✅ フラグメントを展開することをフラグメントスプレッド
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// Request query { user1: user(login: "skmkuma") { ...commonFields # fragmentを展開 } user2: user(login: "skmkuma") { ...commonFields # fragmentを展開 } } # 共通するフィールドを取り出してfragment内に記述 fragment commonFields on User { bio bioHTML avatarUrl company companyHTML createdAt } // Response → 冗長なので省略 |
操作名(Operation Name)
✅ クエリの名前を付与する(Operation nameを付けずにクエリを並列して書くことはできない)
1 2 3 4 5 6 7 8 9 10 11 |
query getUser1{ # オペレーションネームを記述 user(login: "skmkuma") { bio } } query getUser2{ <meta charset="utf-8"># オペレーションネームを記述 user(login: "skmkuma") { bio } } |
変数(Variables)
✅ 引数が動的に変わる場合、”variables”を定義してあげる
1 2 3 4 5 6 7 8 9 10 |
query ($login: String!){ user(login: $login) { bio } } # query variables { "login": "skmkuma" } |
ミューテーション(Mutations)
✅ データの取得に加えて更新・削除したい時に使用
✅ Mutationのリクエストを作成することでデータ操作を行うことができる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# mutationに必要なデータをqueryで取得 // request query repository { repository(name: "git_tutorial", owner: "skmkuma"){ id name url } } // response { "data": { "repository": { "id": "MDEwOlJlcG9zaXRvcnk0MDM2NzA2MzA=", // ←この情報を使い、mutation操作をしていく "name": "git_tutorial", "url": "https://github.com/skmkuma/git_tutorial" } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
//request mutation addStar { addStar(input: { starrableId: "MDEwOlJlcG9zaXRvcnk0MDM2NzA2MzA="}) { starrable { id viewerHasStarred } } } // response { "data": { "addStar": { "starrable": { "id": "MDEwOlJlcG9zaXRvcnk0MDM2NzA2MzA=", "viewerHasStarred": true } } } } |
👇こんな感じでGraphQLを使ってGitHub APIからスターをつけることができました
インラインフラグメント(Inline Fragments)と型名(__typename)
✅ 引数によってレスポンス(返ってくる値)が異なる場合は”… on ○○“とインラインフラグメントを使う
✅ searchフィールドのtypeを”USER”と指定し、nodesフィールドにUser型内のフィールドを展開する
✅ フィールドが同じ型を複数リクエストする場合は”__typename“を記述することで、レスポンスに型名が返ってくる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
// request query searchWithTypeName { search (query: "We work hard", type: USER, first: 2) { nodes { __typename # レスポンスに型名も返ってくるように指定 ... on User { # Userの中のフィールドをnodesフィールド直下に展開 id name url } ... on Organization { # Userの中のフィールドをnodesフィールド直下に展開 id name url projectsUrl } } } } //response { "data": { "search": { "nodes": [ { "__typename": "User", "id": "MDQ6VXNlcjI5NTIxMTQz", "name": "oath-oath", "url": "https://github.com/webengineergh" }, { "__typename": "Organization", "id": "MDEyOk9yZ2FuaXphdGlvbjEyNjI0Njc1", "name": "WeFlex We Code", "url": "https://github.com/weflex", "projectsUrl": "https://github.com/orgs/weflex/projects" } ] } } } |
型システム(Types System)、スカラー型(Scalar Types)、オブジェクト型(Object Types)、スキーマ(Schemas)
✅ 型システム: GraphQLのデータの型は全て、サーバー側で定義される
✅ スキーマ: GraphQL APIの仕様を表現したもの(スキーマ言語で記述される)
✅ スカラー型: これ以上分解できない最小単位(ID, String, Integer, Boolean, Float, ..etc)
✅ オブジェクト型: 1つ以上のスキーマで定義されているフィールドの集合
1 2 3 4 5 6 7 8 9 10 11 12 13 |
type Book { # この集合体がスキーマ id: ID! ←スカラー型(ID) name: String ←スカラー型(String) pageCount: Int ←スカラー型(Int) author: Author ←オブジェクト型(👇Authorスキーマのフィールドの集合) } type Author { id: ID! ←スカラー型(ID) firstName: String ←スカラー型(String) lastName: String ←スカラー型(String) } // 引用⇨ https://qiita.com/NagaokaKenichi/items/d341dc092012e05d6606 |
ページネーション(Pagination)
✅ 最も一般的なページネーション⇨Relay-Style Cursor Pagination
Apolloとは
参考にしたサイト⇨https://qiita.com/jintz/items/4ddc6bf4f95238eff5e9
✅公式HP⇨https://www.apollographql.com/
✅公式ページに記載のある下記の画像が、Apolloの思想の全て
“GraphQLについてのまとめ”は以上になります、いかがだったでしょうか?
概念と考え方をしっかり頭に入れておくとコードを見たときの理解度も変わってきますよね。
まだまだ僕自身も勉強不足の分野ではありますので、しっかりと学んでいきたいです✊
今回はこの辺で、ばいばい👋
コメントを残す