Graphql-quick-guide
GraphQL-はじめに
GraphQLは、RESTful API呼び出しを最適化するためにFacebookによって開発されたオープンソースのサーバー側テクノロジーです。 これは、実行エンジンおよびデータクエリ言語です。 この章では、GraphQLを使用する利点について説明します。
GraphQLを選ぶ理由
RESTful APIは、明確で適切に構造化されたリソース指向のアプローチに従います。 ただし、データがより複雑になると、ルートが長くなります。 1回のリクエストでデータを取得できない場合があります。 これは、GraphQLが便利な場所です。 GraphQLは、データを走査、取得、および変更するための強力なクエリ構文を使用して、データをグラフ形式で構造化します。
以下は、GraphQLクエリ言語を使用する利点です-
あなたが望むものを尋ねる-そしてそれを取得
GraphQLクエリをAPIに送信し、必要なものを正確に取得します。 GraphQLクエリは常に予測可能な結果を返します。 GraphQLを使用するアプリケーションは高速で安定しています。 Restfulサービスとは異なり、これらのアプリケーションは、サーバーから取得するデータを制限できます。
次の例は、これをよりよく理解するのに役立ちます-
属性_id、firstName、lastName_および_collegeName_を持つビジネスオブジェクト_Student_を考えてみましょう。 モバイルアプリケーションが_firstName_と_id_のみを取得する必要があるとします。 _/api/v1/students_のようなRESTエンドポイントを設計すると、_student_オブジェクトのすべてのフィールドのデータを取得することになります。 つまり、データはRESTfulサービスによって過剰に取得されます。 この問題は、GraphQLを使用して解決できます。
以下に示すGraphQLクエリを考慮してください-
{
students {
id
firstName
}
}
これは、idフィールドとfirstnameフィールドの値のみを返します。 クエリは、学生オブジェクトの他の属性の値をフェッチしません。 上記のクエリの応答は以下のとおりです-
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim"
},
{
"id": "S1002",
"firstName": "Kannan"
}
]
}
}
1回のリクエストで多くのリソースを取得する
GraphQLクエリは、関連するビジネスオブジェクトをスムーズに取得するのに役立ちますが、一般的なREST APIは複数のURLからロードする必要があります。 GraphQL APIは、アプリケーションが必要とするすべてのデータを単一のリクエストで取得します。 GraphQLを使用するアプリケーションは、低速のモバイルネットワーク接続でも迅速に実行できます。
名前と場所の属性を持つもう1つのビジネスオブジェクト_College_を考えてみましょう。 Student_ビジネスオブジェクトには、Collegeオブジェクトとの関連付け関係があります。 学生とその大学の詳細を取得するためにREST APIを使用する場合、/api/v1/students_や_/api/v1/colleges_などの2つのリクエストをサーバーに送信することになります。 これにより、リクエストごとにデータのフェッチが不足します。 そのため、モバイルアプリケーションは、目的のデータを取得するためにサーバーに対して複数の呼び出しを行うことを強制されます。
ただし、モバイルアプリケーションは、GraphQLを使用して、単一のリクエストでStudentオブジェクトとCollegeオブジェクトの両方の詳細を取得できます。
以下は、データを取得するGraphQLクエリです-
{
students{
id
firstName
lastName
college{
name
location
}
}
}
上記のクエリの出力には、以下に示すように、要求したフィールドが正確に含まれています-
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim",
"lastName": "Mohammad",
"college": {
"name": "CUSAT",
"location": "Kerala"
}
},
{
"id": "S1002",
"firstName": "Kannan",
"lastName": "Sudhakaran",
"college": {
"name": "AMU",
"location": "Uttar Pradesh"
}
},
{
"id": "S1003",
"firstName": "Kiran",
"lastName": "Panigrahi",
"college": {
"name": "AMU",
"location": "Uttar Pradesh"
}
}
]
}
}
型システムで可能なことを説明する
GraphQLは強く型付けされており、クエリはフィールドとそれに関連付けられたデータ型に基づいています。 GraphQLクエリに型の不一致がある場合、サーバーアプリケーションは明確で役立つエラーメッセージを返します。 これにより、クライアントアプリケーションによるスムーズなデバッグとバグの簡単な検出が可能になります。 GraphQLは、明示的なデータ変換と解析の削減に役立つクライアント側ライブラリも提供します。
_Student_および_College_データ型の例は以下のとおりです-
type Query {
students:[Student]
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
college:College
}
type College {
id:ID!
name:String
location:String
rating:Float
students:[Student]
}
強力な開発者ツールでより速く動く
GraphQLは、文書化とクエリのテストのための豊富な開発者ツールを提供します。 GraphiQLは、クエリとそのスキーマのドキュメントを生成する優れたツールです。 また、クエリの作成中にGraphQL APIとインテリジェントなコード補完機能をテストするクエリエディタも提供します。
GraphQL-環境設定
この章では、GraphQLの環境設定について学習します。 このチュートリアルの例を実行するには、次のものが必要です-
- Linux、macOS、またはWindowsを実行しているコンピューター。
- Webブラウザー、できればGoogle Chromeの最新バージョン。
- Node.jsの最新バージョンがインストールされています。 最新のLTSバージョンが推奨されます。
- VSCode用の拡張GraphQLがインストールされたVisual Studio Codeまたは任意のコードエディター。
NodejsでGraphQLサーバーを構築する方法
以下に示すように、NodejsでGraphQLサーバーを構築するための詳細な段階的なアプローチを実行します-
ステップ1-ノードおよびNpmバージョンを確認する
NodeJsをインストールした後、端末で次のコマンドを使用してノードとnpmのバージョンを確認します-
C:\Users\Admin>node -v
v8.11.3
C:\Users\Admin>npm -v
5.6.0
ステップ2-プロジェクトフォルダーを作成し、VSCodeで開く
プロジェクトのルートフォルダには、test-appという名前を付けることができます。
以下の手順を使用して、Visual Studioコードエディターを使用してフォルダーを開きます-
C:\Users\Admin>mkdir test-app
C:\Users\Admin>cd test-app
C:\Users\Admin\test-app>code.
ステップ3-package.jsonを作成し、依存関係をインストールします
GraphQLサーバーアプリケーションのすべての依存関係を含むpackage.jsonファイルを作成します。
{
"name": "hello-world-server",
"private": true,
"scripts": {
"start": "nodemon --ignore data/server.js"
},
"dependencies": {
"apollo-server-express": "^1.4.0",
"body-parser": "^1.18.3",
"cors": "^2.8.4",
"express": "^4.16.3",
"graphql": "^0.13.2",
"graphql-tools": "^3.1.1"
},
"devDependencies": {
"nodemon": "1.17.1"
}
}
以下のコマンドを使用して依存関係をインストールします-
C:\Users\Admin\test-app>npm install
ステップ4-データフォルダーにフラットファイルデータベースを作成する
この手順では、フラットファイルを使用してデータを保存および取得します。 フォルダーデータを作成し、2つのファイル students.json および colleges.json を追加します。
以下は colleges.json ファイルです-
[
{
"id": "col-101",
"name": "AMU",
"location": "Uttar Pradesh",
"rating":5.0
},
{
"id": "col-102",
"name": "CUSAT",
"location": "Kerala",
"rating":4.5
}
]
以下は students.json ファイルです-
[
{
"id": "S1001",
"firstName":"Mohtashim",
"lastName":"Mohammad",
"email": "[email protected]",
"password": "pass123",
"collegeId": "col-102"
},
{
"id": "S1002",
"email": "[email protected]",
"firstName":"Kannan",
"lastName":"Sudhakaran",
"password": "pass123",
"collegeId": "col-101"
},
{
"id": "S1003",
"email": "[email protected]",
"firstName":"Kiran",
"lastName":"Panigrahi",
"password": "pass123",
"collegeId": "col-101"
}
]
ステップ5-データアクセスレイヤーを作成する
データフォルダーのコンテンツを読み込むデータストアを作成する必要があります。 この場合、コレクション変数_students_および_colleges_が必要です。 アプリケーションがデータを必要とするときはいつでも、これらのコレクション変数を利用します。
次のようにプロジェクトフォルダにファイルdb.jsを作成します-
const { DataStore } = require('notarealdb');
const store = new DataStore('./data');
module.exports = {
students:store.collection('students'),
colleges:store.collection('colleges')
};
ステップ6-スキーマファイルschema.graphqlを作成する
現在のプロジェクトフォルダにスキーマファイルを作成し、次の内容を追加します-
type Query {
test: String
}
ステップ7-リゾルバーファイル、resolvers.jsを作成する
現在のプロジェクトフォルダにリゾルバファイルを作成し、次の内容を追加します-
const Query = {
test: () => 'Test Success, GraphQL server is up & running !!'
}
module.exports = {Query}
ステップ8-「Server.js」を作成し、GraphQLを構成します
サーバーファイルを作成し、GraphQLを次のように設定します-
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const db = require('./db');
const port = process.env.PORT || 9000;
const app = express();
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
app.use(cors(), bodyParser.json());
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
app.listen(
port, () => console.info(
`Server started on port ${port}`
)
);
ステップ9-アプリケーションを実行し、GraphiQLでテストする
次のようにプロジェクトtest-appのフォルダ構造を確認します-
test-app/
-->package.json
-->db.js
-->data
students.json
colleges.json
-->resolvers.js
-->schema.graphql
-->server.js
以下のようにコマンドnpm startを実行します-
C:\Users\Admin\test-app>npm start
サーバーは9000ポートで実行されているため、GraphiQLツールを使用してアプリケーションをテストできます。 ブラウザを開き、URL http://localhost:9000/graphiqlを入力します。 エディタで次のクエリを入力します-
{
Test
}
サーバーからの応答は以下のとおりです-
{
"data": {
"test": "Test Success, GraphQL server is running !!"
}
}
GraphQL-アーキテクチャ
GraphQLは、GraphQLサーバーの動作を記述する仕様です。 これは、サポートされているプロトコル、サーバーが受け入れることができるデータの形式、サーバーから返される応答の形式などのように、要求と応答を処理する方法に関する一連のガイドラインです。 クライアントがGraphQLサーバーに対して行うリクエストは、クエリと呼ばれます。 GraphQLのもう1つの重要な概念は、トランスポート層の診断です。 TCP、websocket、またはその他のトランスポート層プロトコルなど、利用可能なネットワークプロトコルで使用できます。 また、データベースに対して中立なので、リレーショナルデータベースまたはNoSQLデータベースで使用できます。
GraphQL Serverは、以下にリストされている3つの方法のいずれかを使用して展開できます-
- データベースが接続されたGraphQLサーバー
- 既存のシステムを統合するGraphQLサーバー
- ハイブリッドアプローチ
データベースが接続されたGraphQLサーバー
このアーキテクチャには、統合データベースを備えたGraphQLサーバーがあり、多くの場合、新しいプロジェクトで使用できます。 クエリを受信すると、サーバーは要求ペイロードを読み取り、データベースからデータを取得します。 これは、クエリの解決と呼ばれます。 クライアントに返される応答は、公式のGraphQL仕様で指定されている形式に従っています。
上の図では、GraphQLサーバーとデータベースが単一のノードに統合されています。 クライアント(デスクトップ/モバイル)は、GraphQLサーバーとHTTPで通信します。 サーバーはリクエストを処理し、データベースからデータを取得してクライアントに返します。
既存のシステムを統合するGraphQLサーバー
このアプローチは、レガシーインフラストラクチャとさまざまなAPIを持つ企業に役立ちます。 GraphQLを使用すると、既存のシステムでマイクロサービス、レガシーインフラストラクチャ、サードパーティAPIを統合できます。
上の図では、GraphQL APIはクライアントと既存のシステム間のインターフェイスとして機能します。 クライアントアプリケーションはGraphQLサーバーと通信し、サーバーはクエリを解決します。
ハイブリッドアプローチ
最後に、上記の2つのアプローチを組み合わせて、GraphQLサーバーを構築できます。 このアーキテクチャでは、GraphQLサーバーは受信したリクエストを解決します。 接続されたデータベースまたは統合されたAPIからデータを取得します。 これは下図に表されています-
GraphQL-アプリケーションコンポーネント
この章では、さまざまなGraphQLコンポーネントとそれらが相互に通信する方法について説明します。 アプリケーションコンポーネント全体は、次のように区別することができます-
- サーバー側のコンポーネント *クライアント側のコンポーネント
サーバー側のコンポーネント
GraphQLサーバーは、サーバー側のコアコンポーネントを形成し、GraphQLクライアントアプリケーションからのクエリを解析できるようにします。 Apolloサーバーは、最も一般的に使用されるGraphQL仕様の実装です。 他のサーバープログラミングコンポーネントには次のものが含まれます-
Sr.No. | Server Essentials & Description |
---|---|
1 |
GraphQLスキーマは、GraphQLサーバー実装の中心にあり、それに接続するクライアントが利用できる機能を記述します。 |
2 |
Query GraphQLクエリは、データベースまたはレガシーAPIからデータを取得するクライアントアプリケーション要求です。 |
3 |
Resolver リゾルバーは、GraphQL操作をデータに変換するための指示を提供します。 リゾルバ関数を定義することにより、クエリをデータに解決します。 |
クライアント側のコンポーネント
以下は、クライアント側のコンポーネントです-
Sr.No. | Tool & Description |
---|---|
1 |
GraphiQL GraphQLクエリと突然変異を編集およびテストするためのブラウザーベースのインターフェイス。 |
2 |
ApolloClient GraphQLクライアントアプリケーションを構築するための最良のツール。 すべてのjavascriptフロントエンドとうまく統合します。 |
以下の図は、*クライアントサーバーアーキテクチャ*を示しています。 WebサーバーはNodeJとExpressフレームワーク上に構築されています。 ReactJSアプリケーション(Apolloクライアントライブラリを使用して構築)またはGraphiQLブラウザーアプリケーションによって、Apollo GraphQL Serverにリクエストが行われます。 クエリは解析され、サーバーで定義されたスキーマに対して検証されます。 要求スキーマが検証に合格すると、関連付けられたリゾルバー関数が実行されます。 リゾルバーには、APIまたはデータベースからデータを取得するコードが含まれます。
GraphQL-例
この章では、挨拶メッセージHelloWorldを返す簡単なAPIを作成し、GraphiQLを使用してアクセスします。
例
この例は、NodeJS、Express、およびApolloサーバーに基づいています。 私たちは、次の手順ですべての概念をまとめることを学びます-
ステップ1-Expressのセットアップ
ExpressJSは、WebサイトおよびWebアプリケーションの構築を支援するWebアプリケーションフレームワークです。 この例では、Expressフレームワークの上にGraphQL APIを構築します。
次のステップは、 hello-world-server フォルダーを作成し、ターミナルから同じフォルダーに移動することです。 package.jsonを追加し、パッケージに名前を付けます。 このパッケージは内部でのみ使用されるため、プライベートとして宣言できます。
{
"name":"hello-world-server",
"private":true
}
以下に示すように、Expressサーバーの依存関係をインストールします-
C:\Users\Admin\hello-world-server>npm install express body-parser cors
_body-parser_は、ExpressがHTTP Post要求を効率的に処理するのに役立つミドルウェアパッケージです。 _cors_は、クロスオリジンリソース共有を処理する別のミドルウェアパッケージです。
プロジェクトフォルダ内に server.js ファイルを作成し、その中に次を入力します-
const bodyParser = require('body-parser')
const cors = require('cors')
const express = require('express')
const port = process.env.PORT|| 9000
const app = express()
//register middleware
app.use(bodyParser.json() , cors())
app.listen(port, () => console.log(`server is up and running at ${port}`)
Expressサーバーが稼働しているかどうかを確認するには、ターミナルウィンドウで次のコードを実行します-
C:\Users\Admin\hello-world-server>node server.js
サーバーコンソールに次の出力が表示されます。 これは、エクスプレスサーバーがポート9000で実行されていることを示しています。
server is up and running at 9000
ブラウザを開いて http://localhost:9000 と入力すると、次の画面が表示されます-
サーバーを停止するには、 Ctrl + C を押します。
ステップ2-GraphQLおよびApolloサーバーのインストール
Expressが構成されたので、次のステップは、次のGraphQL依存関係をダウンロードすることです-
- graphql
- graphql-tools
- apollo-server-express @ 1
Apolloサーバーv1.0は安定したリリースであるため使用します。 これらの依存関係をインストールするには、次のコマンドを入力します-
C:\Users\Admin\hello-world-server>npm install graphql graphql-tools apollo-server-express@1
これらの依存関係が正常にインストールされているかどうかは、以前に作成した package.json ファイルを確認することで確認できます。
{
"name": "hello-world-server",
"private": true,
"dependencies": {
"apollo-server-express": "^1.4.0",
"body-parser": "^1.18.3",
"cors": "^2.8.4",
"express": "^4.16.3",
"graphql": "^0.13.2",
"graphql-tools": "^3.1.1"
}
}
ステップ3-スキーマを定義する
GraphQLスキーマは、サービスから取得できるオブジェクトの種類とそのフィールドを定義します。 スキーマは GraphQL Schema Definition Language を使用して定義できます。 今、 server.js ファイルに次のコードスニペットを追加します-
//Adding Type Definitions
const typeDefinition = `
type Query {
greeting: String
}
ここで、クエリには_string_値を返す_greeting_属性が含まれています。
ステップ4-リゾルバーを作成する
リゾルバを作成する最初のステップは、グリーティングフィールドのリクエストを処理するコードを追加することです。 これは resolver で指定されます。 リゾルバー関数の構造は、スキーマと一致する必要があります。 server.js ファイルに次のコードスニペットを追加します。
//Adding resolver
const resolverObject = {
Query : {
greeting: () => 'Hello GraphQL From finddevguides !!'
}
}
2番目のステップは、 makeExecutableSchema を使用してスキーマとリゾルバーをバインドすることです。 この関数は、graphql-toolsモジュールで事前に定義されています。 次のコードスニペットを server.js ファイルに追加します。
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs:typeDefinition, resolvers:resolverObject})
ステップ5-ReactJS/GraphiQLアプリケーションからデータを取得するルートを定義する
*server.js* ファイルに次のコードスニペットを追加します-
const {graphqlExpress, graphiqlExpress} = require('apollo-server-express')
//create routes for graphql and graphiql
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
_graphqlExpress_関数は、ルート http://localhost:9000/graphql の登録に役立ちます。 ReactJSアプリケーションは、このエンドポイントを使用してデータを照会できます。 同様に、_graphqliExpress_関数は、ルート http://localhost:9000/graphiql の登録に役立ちます。 これは、APIをテストするためにGraphiQLブラウザクライアントによって使用されます。
完全なserver.jsコードは以下のとおりです-
const bodyParser = require('body-parser')
const cors = require('cors')
const express = require('express')
const port = process.env.PORT||9000
const app = express()
app.use(bodyParser.json() , cors())
const typeDefinition = `
type Query {
greeting: String
}`
const resolverObject = {
Query : {
greeting: () => 'Hello GraphQL From finddevguides !!'
}
}
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs:typeDefinition, resolvers:resolverObject})
const {graphqlExpress,graphiqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
app.listen(port, () => console.log(`server is up and running ${port}`))
ステップ6-アプリケーションを開始する
次のようにNode.jsを使用して server.js を実行します-
C:\Users\Admin\hello-world-server>node server.js
ステップ7-GraphQL APIをテストする
ブラウザを開き、「 http://localhost:9000/graphiql 」と入力します。 GraphiQLのクエリタブで、次を入力します-
{
greeting
}
サーバーからの応答は以下のとおりです-
{
"data": {
"greeting": "Hello GraphQL From finddevguides !!"
}
}
次の画像は、応答を示しています-
注-Apollo Serverバージョン1.0が使用されていることを確認してください。
GraphQL-タイプシステム
GraphQLは強く型付けされた言語です。 型システムは、GraphQLアプリケーションで使用できるさまざまなデータ型を定義します。 型システムは、クライアントとサーバー間の契約であるスキーマの定義に役立ちます。 一般的に使用されるGraphQLデータ型は次のとおりです-
Sr.No. | Types & Description |
---|---|
1 |
Scalar 単一の値を格納します |
2 |
Object 取得できるオブジェクトの種類を示します |
3 |
Query 他の特定のタイプへのエントリポイントタイプ |
4 |
Mutation データ操作のエントリポイント |
5 |
Enum ユーザーが所定のオプションリストから選択する必要がある状況で役立ちます。 |
スカラー型
スカラー型は、単一の値のみを格納できるプリミティブデータ型です。 GraphQLが提供するデフォルトのスカラー型は-
- Int -符号付き32ビット整数
- Float -符号付きの倍精度浮動小数点値
- String -UTF-8文字のシーケンス
- ブール-真または偽
- ID -一意の識別子。多くの場合、オブジェクトを取得するための一意の識別子として、またはキャッシュのキーとして使用されます。
スカラー型を定義するための構文は次のとおりです-
field: data_type
以下のスニペットは、string値を返すgreetingという名前のフィールドを定義しています。
greeting: String
オブジェクトタイプ
オブジェクトタイプは、スキーマで使用される最も一般的なタイプであり、フィールドのグループを表します。 オブジェクトタイプ内の各フィールドは別のタイプにマップされるため、ネストされたタイプが許可されます。 つまり、オブジェクト型は複数のスカラー型またはオブジェクト型で構成されます。
オブジェクトタイプを定義するための構文は次のとおりです-
type object_type_name
{
field1: data_type
field2:data_type
....
fieldn:data_type
}
あなたは次のコードスニペットを考慮することができます-
--Define an object type--
type Student {
stud_id:ID
firstname: String
age: Int
score:Float
}
--Defining a GraphQL schema--
type Query
{
stud_details:[Student]
}
上記の例では、オブジェクトデータ型Studentを定義しています。 ルートQueryスキーマの_stud_details_フィールドは、Studentオブジェクトのリストを返します。
クエリタイプ
GraphQLクエリを使用してデータを取得します。 RESTベースのAPIでリソースを要求するようなものです。 簡単にするために、クエリタイプはクライアントアプリケーションからGraphQLサーバーに送信されるリクエストです。 GraphQLは、*スキーマ定義言語(SDL)*を使用してクエリを定義します。 クエリタイプは、GraphQLの多くのルートレベルタイプの1つです。
クエリを定義するための構文は以下のとおりです-
type Query {
field1: data_type
field2:data_type
field2(param1:data_type,param2:data_type,...paramN:data_type):data_type
}
クエリを定義する例-
type Query {
greeting: String
}
変異タイプ
突然変異は、データを作成、更新、または削除するためにサーバーに送信される操作です。 これらは、RESTベースのAPIを呼び出すPUT、POST、PATCHおよびDELETE動詞に類似しています。
突然変異は、GraphQLのルートレベルのデータ型の1つです。 Queryタイプはデータ取得操作のエントリポイントを定義し、Mutationタイプはデータ操作操作のエントリポイントを指定します。
突然変異の種類を定義するための構文は以下のとおりです-
type Mutation {
field1: data_type
field2(param1:data_type,param2:data_type,...paramN:data_type):data_type
}
たとえば、次のように突然変異のタイプを定義して新しい生徒を追加できます-
type Mutation {
addStudent(firstName: String, lastName: String): Student
}
列挙型
Enumはスカラー型に似ています。 列挙型は、フィールドの値が所定のオプションリストからのものでなければならない状況で役立ちます。
列挙型を定義するための構文は次のとおりです-
type enum_name{
value1
value2
}
次のスニペットは、列挙型を定義する方法を示しています-
type Days_of_Week{
SUNDAY
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
}
リストタイプ
リストを使用して、特定のタイプの値の配列を表すことができます。 リストは、オブジェクト型、スカラー、および列挙型をラップする型修飾子[]で定義されます。
次の構文は、リストタイプを定義するために使用することができます-
field:[data_type]
以下の例では、リストタイプのtodosを定義しています-
type Query {
todos: [String]
}
Null不可タイプ
デフォルトでは、各コアスカラータイプをnullに設定できます。 つまり、これらの型は指定された型の値を返すか、値を持たないかのいずれかです。 このデフォルトをオーバーライドし、フィールドを定義する必要があることを指定するには、感嘆符(!)をタイプに追加できます。 これにより、クエリによって返される結果に値が存在することが保証されます。
次の構文を使用して、null不可フィールドを定義できます-
field:data_type!
以下の例では、_stud_id_が必須フィールドとして宣言されています。
type Student {
stud_id:ID!
firstName:String
lastName:String
fullName:String
college:College
}
GraphQL-スキーマ
GraphQLスキーマは、GraphQLサーバー実装の中核です。 接続するクライアントアプリケーションで使用可能な機能について説明します。 任意のプログラミング言語を使用して、GraphQLスキーマを作成し、その周りのインターフェイスを構築できます。
GraphQLランタイムは、一般的なグラフベースのスキーマを定義して、それが表すデータサービスの機能を公開します。 クライアントアプリケーションは、その機能内でスキーマを照会できます。 このアプローチにより、クライアントはサーバーから切り離され、独立して進化と拡張の両方が可能になります。
この章では、Apolloサーバーを使用してGraphQLクエリを実行します。 graphql-toolsの makeExecutableSchema 関数は、スキーマとリゾルバーをバインドするのに役立ちます。
makeExecutableSchema関数の構文
*makeExecutableSchema* 関数は、オブジェクト型の単一の引数\ {}を取ります。 この関数を使用するための構文は以下のとおりです-
import { makeExecutableSchema } from 'graphql-tools';
const jsSchema = makeExecutableSchema({
typeDefs,
resolvers,//optional
logger,//optional
allowUndefinedInResolve = false,//optional
resolverValidationOptions = {},//optional
directiveResolvers = null,//optional
schemaDirectives = null, //optional
parseOptions = {}, //optional
inheritResolversFromInterfaces = false //optional
});
Sr.No. | Parameter & Description |
---|---|
1 |
typeDefs これは必須の引数です。 GraphQLクエリをUTF-8文字列として表します。 |
2 |
Resolvers これはオプションの引数です(デフォルトでは空のオブジェクト)。 これには、クエリを処理する関数があります。 |
3 |
logger これはオプションの引数であり、エラーをサーバーコンソールに出力するために使用できます。 |
4 |
parseOptions これはオプションの引数であり、typeDefsを文字列として指定するときに解析をカスタマイズできます。 |
5 |
allowUndefinedInResolve これはデフォルトで当てはまります。 falseに設定すると、resolve関数が未定義を返す場合にエラーをスローします。 |
6 |
resolverValidationOptions これはオプションの引数であり、ブールプロパティを持つオブジェクトを受け入れます。 |
7 |
inheritResolversFromInterfaces これはオプションの引数であり、ブール引数を受け入れてリゾルバオブジェクトの継承を確認します。 |
図
このスキーマを理解するための簡単なアプリケーションを作成しましょう。 これにより、サーバーから生徒のリストを照会するためのスキーマが作成されます。 学生データはフラットファイルに保存され、 notarealdb というノードモジュールを使用してデータベースを偽造し、フラットファイルから読み取ります。
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
*schema-app* という名前のフォルダーを作成します。 ターミナルからディレクトリをschema-appに変更します。 次に、環境設定の章で説明されているステップ3から5に従って、ダウンロードとインストールプロセスを完了します。
ステップ2-スキーマを作成する
プロジェクトフォルダに schema.graphql ファイル、 schema-app を追加し、次のコードを追加します-
type Query {
greeting:String
students:[Student]
}
type Student {
id:ID!
firstName:String
lastName:String
password:String
collegeId:String
}
スキーマのルートはクエリタイプになります。 クエリには、挨拶と、それぞれ文字列と生徒のリストを返す生徒の2つのフィールドがあります。 学生は複数のフィールドを含むため、オブジェクト型として宣言されます。 IDフィールドは、null不可として宣言されています。
ステップ3-リゾルバーを作成する
プロジェクトフォルダにファイル resolvers.js を作成し、次のコードを追加します-
const db = require('./db')
const Query = {
greeting:() => {
return "hello from finddevguides !!!"
},
students:() => db.students.list()
}
module.exports = {Query}
ここで、挨拶と生徒はクエリを処理するリゾルバです。 * students resolver関数*は、データアクセスレイヤーから学生のリストを返します。 モジュール外のリゾルバー関数にアクセスするには、 module.exports を使用してQueryオブジェクトをエクスポートする必要があります。
ステップ4-アプリケーションを実行する
server.jsファイルを作成し、環境設定の章のステップ8を参照してください。 次のステップは、ターミナルでコマンドnpm startを実行することです。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。 ブラウザーを開き、URL http://localhost:9000/graphiql を入力します。
エディタで次のクエリを入力します-
{
greeting
students {
id
firstName
lastName
}
}
クエリは、次のように出力を表示します-
注-student.jsonをRESTful API呼び出しに置き換えて、学生データまたはMySQLやMongoDBなどの実際のデータベースを取得することもできます。 GraphQLは、パフォーマンスを改善するために元のアプリケーションレイヤーの薄いラッパーになります。
GraphQL-リゾルバー
リゾルバーは、GraphQLクエリの応答を生成する関数のコレクションです。 簡単に言えば、リゾルバーはGraphQLクエリハンドラーとして機能します。 GraphQLスキーマのすべてのリゾルバ関数は、以下に示す4つの位置引数を受け入れます-
fieldName:(root, args, context, info) => { result }
リゾルバ関数の例を以下に示します-
//resolver function with no parameters and returning string
greeting:() => {
return "hello from finddevguides !!!"
}
//resolver function with no parameters and returning list
students:() => db.students.list()
//resolver function with arguments and returning object
studentById:(root,args,context,info) => {
return db.students.get(args.id);
}
以下は、位置引数とその説明です-
Sr.No. | Arguments & Description |
---|---|
1 |
root 親フィールドのリゾルバーから返された結果を含むオブジェクト。 |
2 |
args クエリのフィールドに渡される引数を持つオブジェクト。 |
3 |
context これは、特定のクエリのすべてのリゾルバーによって共有されるオブジェクトです。 |
4 |
info これには、フィールド名、ルートからフィールドへのパスなど、クエリの実行状態に関する情報が含まれています。 |
リゾルバー結果の形式
GraphQLのリゾルバは、以下に示すように異なるタイプの値を返すことができます-
Sr.No. | Arguments and Description |
---|---|
1 |
null or undefined これは、オブジェクトが見つからなかったことを示します |
2 |
array これは、スキーマがフィールドの結果がリストであることを示している場合にのみ有効です |
3 |
promise リゾルバは、多くの場合、データベースまたはバックエンドAPIからのフェッチなどの非同期アクションを実行するため、約束を返すことができます |
4 |
scalar or object リゾルバは他の値を返すこともできます |
図
リゾルバを理解するための簡単なアプリケーションを作成しましょう。 これにより、サーバーからIDで学生を照会するためのスキーマが作成されます。 学生データはフラットファイルに保存され、 notarealdb というノードモジュールを使用してデータベースを偽造し、フラットファイルから読み取ります。
以下は、単純なアプリケーションを作成するための段階的なプロセスです-
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
*resolver-app* という名前のフォルダーを作成します。 ターミナルからディレクトリを *resolver-app* に変更します。 後で、環境設定の章の手順3〜5に従います。
ステップ2-スキーマを作成する
プロジェクトフォルダresolver-appにschema.graphqlファイルを追加し、次のコードを追加します-
type Query {
greeting:String
students:[Student]
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
password:String
collegeId:String
}
スキーマファイルは、ユーザーが_greeting、students_、および_studentById_を照会できることを示しています。 特定のIDを持つ生徒を取得するには、*データ型ID!*を使用します。 _students_フィールドは生徒の配列を返し、_greeting_は単純な文字列値を返します。
ステップ3-リゾルバーを作成する
プロジェクトフォルダにファイル resolvers.js を作成し、次のコードを追加します-
const db = require('./db')
const Query = {
//resolver function for greeting
greeting:() => {
return "hello from finddevguides !!!"
},
//resolver function for students returns list
students:() => db.students.list(),
//resolver function for studentbyId
studentById:(root,args,context,info) => {
//args will contain parameter passed in query
return db.students.get(args.id);
}
}
module.exports = {Query}
ここで、_studentById_は3つのパラメーターを取ります。 この章で説明したように、_studentId_はargsから取得できます。ルートにはQueryオブジェクト自体が含まれます。 特定の生徒を返すには、studentsコレクションのidパラメーターを使用してgetメソッドを呼び出す必要があります。
ここで、_greeting、students、studentById_は、クエリを処理するリゾルバです。 * students resolver関数*は、データアクセスレイヤーから学生のリストを返します。 モジュール外のリゾルバー関数にアクセスするには、module.exportsを使用してQueryオブジェクトをエクスポートする必要があります。
ステップ4-アプリケーションを実行する
server.jsファイルを作成します。 環境設定の章の手順8を参照してください。 ターミナルでコマンドnpm startを実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
ブラウザを開き、URL http://localhost:9000/graphiql を入力します。 エディタで次のクエリを入力します-
{
studentById(id:"S1001") {
id
firstName
lastName
}
}
上記のクエリの出力は以下のとおりです-
{
"data": {
"studentById": {
"id": "S1001",
"firstName": "Mohtashim",
"lastName": "Mohammad"
}
}
}
GraphQL-クエリ
GraphQL操作は、読み取り操作または書き込み操作のいずれかです。 GraphQLクエリは値の読み取りまたはフェッチに使用され、突然変異は値の書き込みまたはポストに使用されます。 どちらの場合でも、操作はGraphQLサーバーが特定の形式のデータで解析して応答できる単純な文字列です。 モバイルおよびWebアプリケーションで通常使用される一般的な応答形式はJSONです。
クエリを定義する構文は次のとおりです-
//syntax 1
query query_name{ someField }
//syntax 2
{ someField }
以下はクエリの例です-
//query with name myQuery
query myQuery{
greeting
}
//query without any name
{
greeting
}
上記の例から、クエリキーワードがオプションであることは明らかです。
GraphQLクエリは、データの過剰なフェッチを減らすのに役立ちます。 Restful APIとは異なり、GraphQLでは、ユーザーはサーバーから取得するフィールドを制限できます。 これは、ネットワーク上のクエリが小さくなり、トラフィックが少なくなることを意味します。これにより、応答時間が短縮されます。
図1-カスタムフィールドを使用した学生モデルのクエリ
この例では、jsonファイルに格納された学生のセットがあります。 各学生モデルには、firstName、lastName、idなどのフィールドがありますが、fullNameはありません。 ここでは、すべての学生のfullNameを取得するクエリを作成する方法について説明します。 そのためには、両方のスキーマリゾルバーでfullNameフィールドを作成する必要があります。
以下の手順を使用してこの図を行う方法を見てみましょう-
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
*query-app* という名前のフォルダーを作成します。 端末からディレクトリを *query-app* に変更します。 後で、環境設定の章で説明されている手順3〜5に従います。
ステップ2-スキーマを作成する
プロジェクトフォルダquery-appに schema.graphql ファイルを追加し、次のコードを追加します-
type Query {
greeting:String
students:[Student]
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
}
*students.json* ファイルには_fullName_フィールドがないことに注意してください。 ただし、クエリを介して生徒の_fullname_を取得する必要があります。 この場合の_fullName_は、データソースでは使用できないカスタムフィールドになります。
ステップ3-リゾルバーを作成する
プロジェクトフォルダにファイル resolvers.js を作成し、次のコードを追加します-
const db = require('./db')
const Query = {
//resolver function for greeting
greeting:() => {
return "hello from finddevguides !!!"
},
//resolver function for students returns list
students:() => db.students.list(),
//resolver function for studentbyId
studentById:(root,args,context,info) => {
//args will contain parameter passed in query
return db.students.get(args.id);
}
}
//for each single student object returned,resolver is invoked
const Student = {
fullName:(root,args,context,info) => {
return root.firstName+":"+root.lastName
}
}
module.exports = {Query,Student}
ステップ4-アプリケーションを実行する
*server.js* ファイルを作成します。 環境設定の章の手順8を参照してください。 ターミナルでコマンド_npm_ startを実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
ブラウザーを開き、URL http://localhost:9000/graphiql を入力します。 エディタで次のクエリを入力します-
{
students{
id
fullName
}
}
クエリの応答は以下のとおりです-
{
"data": {
"students": [
{
"id": "S1001",
"fullName": "Mohtashim:Mohammad"
},
{
"id": "S1002",
"fullName": "Kannan:Sudhakaran"
},
{
"id": "S1003",
"fullName": "Kiran:Panigrahi"
}
]
}
}
*server.js* を作成し、次のコードを追加します-
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const db = require('./db');
const port = 9000;
const app = express();
//loading type definitions from schema file
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
//loading resolvers
const resolvers = require('./resolvers')
//binding schema and resolver
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
//enabling cross domain calls and form post
app.use(cors(), bodyParser.json());
//enabling routes
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
//registering port
app.listen(port, () => console.info(`Server started on port ${port}`));
ターミナルでコマンドnpm startを実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
ブラウザを開き、URL http://localhost:9000/graphiql を入力します。 エディタで次のクエリを入力します-
{
students{
id
fullName
}
}
クエリの応答は以下のとおりです-
{
"data": {
"students": [
{
"id": "S1001",
"fullName": "Mohtashim:Mohammad"
},
{
"id": "S1002",
"fullName": "Kannan:Sudhakaran"
},
{
"id": "S1003",
"fullName": "Kiran:Panigrahi"
}
]
}
}
図2-ネストされたクエリ
学生の詳細と大学の詳細を取得するためのネストされたクエリを作成しましょう。 同じプロジェクトフォルダーで作業します。
ステップ1-スキーマの編集
スキーマファイルには既に_student_フィールドがあります。 フィールドカレッジを追加して、そのタイプを定義しましょう。
type College {
id:ID!
name:String
location:String
rating:Float
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
college:College
}
ステップ2-resolver.jsを変更する
以下のように大学リゾルバ関数を追加する必要があります。 大学リゾルバ関数は、返された各学生オブジェクトに対して実行されます。 この場合のリゾルバーのルートパラメーターには、_student_が含まれます。
const Student = {
fullName:(root,args,context,info) => {
return root.firstName+":"+root.lastName
},
college:(root) => {
return db.colleges.get(root.collegeId);
}
}
module.exports = {Query,Student}
リゾルバは、カレッジコレクションのgetメソッドを呼び出して_collegeId_を渡すことにより、各学生のカレッジを返します。 _collegeId_を介してStudentとCollegeの間に関連付け関係があります。
ステップ3-アプリケーションをテストする
ターミナルウィンドウを開き、プロジェクトフォルダーに移動します。 コマンド-npm startを入力します。 ブラウザを起動し、URL http://localhost:9000/graphiql を入力します。
GraphiQLウィンドウで次のクエリを入力します-
{
students{
id
firstName
college {
id
name
location
rating
}
}
}
クエリの応答は以下のとおりです-
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim",
"college": {
"id": "col-102",
"name": "CUSAT",
"location": "Kerala",
"rating": 4.5
}
},
{
"id": "S1002",
"firstName": "Kannan",
"college": {
"id": "col-101",
"name": "AMU",
"location": "Uttar Pradesh",
"rating": 5
}
},
{
"id": "S1003",
"firstName": "Kiran",
"college": {
"id": "col-101",
"name": "AMU",
"location": "Uttar Pradesh",
"rating": 5
}
}
]
}
}
クエリ変数とは何ですか?
クエリに渡す動的な値がある場合、変数を使用してこれらの動的な値を表します。 したがって、クライアントアプリケーションでクエリを再利用できます。
図
クエリ変数を理解するための簡単なアプリケーションを作成しましょう。
ステップ1-スキーマファイルの編集
文字列パラメーターを取り、文字列を返す_sayHello_フィールドを追加します。 クライアントアプリケーションでは、名前の値は動的になります。
type Query {
sayHello(name:String!):String
}
ステップ2-resolver.jsファイルの編集
以下のようにパラメータを取る_sayHello_リゾルバを追加します-
sayHello:(root,args,context,info) => `Hi ${args.name} GraphQL server says Hello to you!!`
ステップ3-GraphiQLでクエリ変数を宣言する
変数は、変数名の後に$を付けて宣言されます。 例:$ myname_Variable。
$ myname_Variableを宣言したら、名前付きクエリ構文で使用する必要があります。 クエリ、myQueryは文字列値を取り、以下に示すようにsayHelloに渡します-
query myQuery($myname_Variable:String!) {
sayHello(name:$myname_Variable)
}
GraphiQLクライアントのQuery Variablesセクションで、$ myname_Variableの値をJSONオブジェクトとして設定します。
{
"myname_Variable": "Mohtashim"
}
上記のコードの出力は次のとおりです-
{
"data": {
"sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
}
}
Enumでクエリ変数を使用する方法
フィールドパラメータが enum type の場合のクエリ変数の使用方法を見てみましょう。
ステップ1-schema.graphqlファイルの編集
enum ColorType {
RED
BLUE
GREEN
}
type Query {
setFavouriteColor(color:ColorType):String
}
_setFavouriteColor_関数は、enumを入力として受け取り、文字列値を返します。
ステップ2-resolvers.jsファイルの編集
リゾルバー関数_setFavouriteColor_は、_root_と_args_を取ります。 実行時に関数に渡される列挙値には、argsパラメーターを使用してアクセスできます。
setFavouriteColor:(root,args) => {
return "Your Fav Color is :"+args.color;
}
ステップ3-GraphiQLでクエリ変数を宣言する
クエリの名前は query_to_setColor で、ColorTypeの名前color_variableの変数を取ります。 この変数は、setFavouriteColorメソッドに渡されます。
query query_to_setColor($color_variable:ColorType) {
setFavouriteColor(color:$color_variable)
}
GraphiQLのクエリ変数セクションで、次のコードを入力します-
{
"color_variable":"RED"
}
応答は以下に示されています-
{
"data": {
"setFavouriteColor": "Your Fav Color is: RED"
}
}
GraphQL-突然変異
この章では、GraphQLで突然変異クエリを学習します。
突然変異クエリは、データストア内のデータを変更し、値を返します。 データの挿入、更新、削除に使用できます。 突然変異は、スキーマの一部として定義されます。
変異クエリの構文は以下のとおりです-
mutation{
someEditOperation(dataField:"valueOfField"):returnType
}
図
突然変異クエリを使用して、新しい学生レコードをデータストアに追加する方法を理解しましょう。
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
名前mutation-appでプロジェクトフォルダを作成します。 ターミナルからディレクトリを「mutation-app」に変更します。 環境設定の章で説明されている手順3〜5に従います。
ステップ2-schema.graphql Fileの作成
プロジェクトフォルダmutation-appに schema.graphql ファイルを追加し、次のコードを追加します-
type Query {
greeting:String
}
type Mutation {
createStudent(collegeId:ID,firstName:String,lastName:String):String
}
関数createStudentはString型を返すことに注意してください。 これは、学生の作成後に生成される一意の識別子(ID)です。
ステップ3-resolver.jsファイルを作成する
プロジェクトフォルダにファイルresolvers.jsを作成し、次のコードを追加します-
const db = require('./db')
const Mutation = {
createStudent:(root,args,context,info) => {
return db.students.create({collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName})
}
}
const Query = {
greeting:() => "hello"
}
module.exports = {Query,Mutation}
突然変異関数は、データストア内の学生コレクションを指します。 新しい_student_を追加するには、studentsコレクションでcreateメソッドを呼び出します。 _args_オブジェクトには、クエリで渡されるパラメーターが含まれます。 _students_コレクションのcreateメソッドは、新しく作成された学生オブジェクトのIDを返します。
ステップ4-アプリケーションを実行する
*server.js* ファイルを作成します。 環境設定の章の手順8を参照してください。 ターミナルでコマンドnpm startを実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
次のステップは、ブラウザーを開いてURL http://localhost:9000/graphiql を入力することです。 エディタで次のクエリを入力します-
//college Id should be matched with data from colleges.json for easy retrieval
mutation {
createStudent(collegeId:"col-2",firstName:"Tim",lastName:"George")
}
上記のクエリは、student.jsonファイルに学生オブジェクトを作成します。 クエリは一意の識別子を返します。 クエリの応答は以下のとおりです-
{
"data": {
"createStudent": "SkQtxYBUm"
}
}
学生オブジェクトが作成されたかどうかを確認するには、studentByIdクエリを使用できます。 データフォルダから「students.json」ファイルを開いてIDを確認することもできます。
studentById queryを使用するには、以下に示すように schema.graphql を編集します-
type Query {
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
collegeId:String
}
以下のように resolver.js ファイルを編集します-
const db = require('./db')
const Query = {
studentById:(root,args,context,info) => {
return db.students.get(args.id);
}
}
const Mutation = {
createStudent:(root,args,context,info) => {
return db.students.create({collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName})
}
}
module.exports = {Query,Mutation}
以下に示すのは、突然変異クエリから返された一意のIDで学生を取得するクエリです-
{
studentById(id:"SkQtxYBUm") {
id
firstName
lastName
}
}
サーバーからの応答は次のとおりです-
{
"data": {
"studentById": {
"id": "SkQtxYBUm",
"firstName": "Tim",
"lastName":"George"
}
}
}
ミューテーションでオブジェクトを返す
突然変異したオブジェクトを返すことをお勧めします。 たとえば、クライアントアプリケーションは学生と大学の詳細を取得する必要があります。 この場合、2つの異なるリクエストを作成する代わりに、学生とその大学の詳細を含むオブジェクトを返すクエリを作成できます。
ステップ1-スキーマファイルの編集
*addStudent* という名前の新しいメソッドを追加します。このメソッドは、 *schema.graphql* の突然変異タイプのオブジェクトを返します。
学生の詳細から大学の詳細にアクセスする方法を学びましょう。 スキーマファイルにカレッジタイプを追加します。
type Mutation {
addStudent_returns_object(collegeId:ID,firstName:String,lastName:String):Student
createStudent(collegeId:ID,firstName:String,lastName:String):String
}
type College {
id:ID!
name:String
location:String
rating:Float
}
type Student {
id:ID!
firstName:String
lastName:String
college:College
}
ステップ2-「resolvers.js」ファイルを更新する
プロジェクトフォルダ内のファイル resolvers.js を更新し、次のコードを追加します-
const Mutation = {
createStudent:(root,args,context,info) => {
return db.students.create({
collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName
})
},
//new resolver function
addStudent_returns_object:(root,args,context,info) => {
const id = db.students.create({
collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName
})
return db.students.get(id)
}
}
//for each single student object returned,resolver is invoked
const Student = {
college:(root) => {
return db.colleges.get(root.collegeId);
}
}
module.exports = {Query,Student,Mutation}
ステップ3-サーバーを起動し、GraphiQLに要求クエリを入力します
次に、サーバーを起動し、次のコードでGraphiQLのクエリを要求します-
mutation {
addStudent_returns_object(collegeId:"col-101",firstName:"Susan",lastName:"George") {
id
firstName
college{
id
name
}
}
}
上記のクエリは、新しい学生を追加し、学生オブジェクトと大学オブジェクトを取得します。 これにより、サーバーへの往復が節約されます。
応答は以下のとおりです-
{
"data": {
"addStudent_returns_object": {
"id": "rklUl08IX",
"firstName": "Susan",
"college": {
"id": "col-101",
"name": "AMU"
}
}
}
}
GraphQL-検証
データを追加または変更するときは、ユーザー入力を検証することが重要です。 たとえば、フィールドの値が常にnullでないことを確認する必要がある場合があります。 *を使用できます! (null不可)*このような検証を実行するためのGraphQLのタイプマーカー。
- !*タイプマーカーを使用するための構文は以下のとおりです-
type TypeName {
field1:String!,
field2:String!,
field3:Int!
}
上記の構文は、すべてのフィールドがnullでないことを保証します。
文字列の長さをチェックしたり、数値が特定の範囲内にあるかどうかをチェックするなどの追加のルールを実装する場合は、カスタムバリデーターを定義できます。 カスタム検証ロジックは、リゾルバー関数の一部になります。 例の助けを借りてこれを理解しましょう。
図-カスタムバリデーターの実装
基本的な検証を行ったサインアップフォームを作成しましょう。 フォームには、メール、名、およびパスワードのフィールドがあります。
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
*validation-app* という名前のフォルダーを作成します。 ターミナルからディレクトリを「検証アプリ」に変更します。 環境設定の章で説明されている手順3〜5に従います。
ステップ2-スキーマを作成する
プロジェクトフォルダーに schema.graphql ファイルを追加します
type Query {
greeting:String
}
type Mutation {
signUp(input:SignUpInput):String
}
input SignUpInput {
email:String!,
password:String!,
firstName:String!
}
注-signUpInputの入力タイプを使用して、signUp関数のパラメーターの数を減らすことができます。 したがって、signUp関数は、SignUpInput型のパラメーターを1つだけ受け取ります。
ステップ3-リゾルバーを作成する
プロジェクトフォルダにファイル resolvers.js を作成し、次のコードを追加します-
const Query = {
greeting:() => "Hello"
}
const Mutation ={
signUp:(root,args,context,info) => {
const {email,firstName,password} = args.input;
const emailExpression =/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const isValidEmail = emailExpression.test(String(email).toLowerCase())
if(!isValidEmail)
throw new Error("email not in proper format")
if(firstName.length > 15)
throw new Error("firstName should be less than 15 characters")
if(password.length < 8 )
throw new Error("password should be minimum 8 characters")
return "success";
}
}
module.exports = {Query,Mutation}
リゾルバ関数は、「signUp」パラメータ、「email」、「password」、「firstName」を受け入れます。 これらはargs.inputを通じてアクセスできるように、input変数を介して渡されます。
ステップ4-アプリケーションを実行する
server.jsファイルを作成します。 環境設定の章の手順8を参照してください。 ターミナルでコマンド_npm start_を実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
ブラウザーを開き、URL http://localhost:9000/graphiql を入力します。 エディタで次のクエリを入力します-
mutation doSignUp($input:SignUpInput) {
signUp(input:$input)
}
サインアップ関数への入力は複合型であるため、graphiqlでクエリ変数を使用する必要があります。 このために、最初にクエリに名前を付け、doSignUpと呼ぶ必要があります。「$ input」はクエリ変数です。
graphiqlのクエリ変数タブに次のクエリ変数を入力する必要があります-
{
"input":{
"email": "abc@abc",
"firstName": "kannan",
"password": "pass@1234"
}
}
エラー配列には、以下に示すように検証エラーの詳細が含まれています-
{
"data": {
"signUp": null
},
"errors": [
{
"message": "email not in proper format",
"locations": [
{
"line": 2,
"column": 4
}
],
"path": [
"signUp"
]
}
]
}
以下に示すように、各フィールドに適切な入力を入力する必要があります-
{
"input":{
"email": "[email protected]",
"firstName": "kannan",
"password": "pass@1234"
}
}
応答は次のとおりです-
{
"data": {
"signUp": "success"
}
}
ここで、以下のクエリでは、パスワードを割り当てていません。
{
"input":{
"email": "[email protected]",
"firstName": "kannan"
}
}
必須フィールドが提供されていない場合、qraphqlサーバーは次のエラーを表示します-
{
"errors": [
{
"message": "Variable \"$input\" got invalid value {\"email\":\"[email protected]\",\"firstName\":\"kannan\"}; Field value.password of required type String! was not provided.",
"locations": [
{
"line": 1,
"column": 19
}
]
}
]
}
GraphQL-JQuery統合
Webアプリケーションは、データを非同期で(バックグラウンドで)送受信します。 AJAXを使用すると、Webサイトはページを更新せずにコンテンツを画面にロードできます。 jQueryにはAJAX機能用のメソッドがいくつか用意されているため、AJAXの使用が簡単になります。 この章では、GraphQLをjQueryと統合する方法を学習します。
クライアントサーバーアーキテクチャを使用するアプリケーションを検討してください。 GraphQLサーバーにデータを要求するフロントエンドWebページを構築できます。 Webページは、jQueryを使用してGraphQLサーバーにAJAX呼び出しを行います。
GraphQLをJQueryに統合するには、GraphiQLリクエストヘッダーを調べて、リクエストパラメーターを理解しましょう。
*hello-world* アプリを起動します(関連する図については、第6章を参照してください)。 GraphiQLウィンドウにgraphqlクエリ\ {greeting}を入力します。 右クリックして検査するか、クロムで(Ctrl + Shift + I)を押して、以下に示すようにネットワークタブに移動します-
単純な hello-world の例から、使用される* httpメソッド*が POST であることがわかります。 ブラウザで、ヘッダーセクションまでスクロールダウンして、_requestペイロード_を表示します。
[コードを表示]をクリックすると、Chromeのリクエストペイロードセクションに以下が表示されます。
{"query":"{\n greeting\n}","variables":null,"operationName":null}
また、クライアントアプリケーションから呼び出す必要がある要求URL http://localhost:9000/graphql にも注意してください。
図
段階的なプロセスを使用して、GraphQLとJQueryを統合する方法を理解しましょう。
サーバーのセットアップ
私たちは、次の手順を使用してサーバーをセットアップすることを学びます-
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
*jquery-server-app* という名前のフォルダーを作成します。 ターミナルからディレクトリをjquery-server-appに変更します。 環境設定の章で説明されている手順3〜5に従います。
ステップ2-スキーマを作成する
プロジェクトフォルダ jquery-server-app にschema.graphqlファイルを追加し、次のコードを追加します-
type Query
{
greeting: String
sayHello(name:String!):String
}
ファイルには、 greeting と sayHello という2つのクエリが定義されています。 saysayelloクエリは、文字列パラメーターを受け取り、別の文字列を返します。 saysayello()関数のパラメーターがnullではありません。
ステップ3-リゾルバーを作成する
プロジェクトフォルダにファイルresolvers.jsを作成し、次のコードを追加します-
const Query =
{
greeting: () => 'Hello GraphQL From finddevguides !!' ,
sayHello:(root,args,context,info) => `Hi ${args.name} GraphQL server says Hello to you!!`
}
module.exports = {Query}
ここで、 greeting と sayHello は2つのリゾルバです。 sayHelloResolverでは、nameパラメーターに渡された値は、argsを介してアクセスできます。 モジュール外のリゾルバー関数にアクセスするには、 module.exports を使用してQueryオブジェクトをエクスポートする必要があります。
ステップ4-アプリケーションを実行する
server.jsファイルを作成します。 環境設定の章の手順8を参照してください。 ターミナルでコマンド_npm start_を実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
ブラウザを開き、URL http://localhost:9000/graphiql を入力します。 エディタで次のクエリを入力します-
{
greeting,
sayHello(name:"Mohtashim")
}
サーバーからの応答は以下のとおりです-
{
"data": {
"greeting": "Hello GraphQL From finddevguides !!",
"sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
}
}
クライアントのセットアップ
すでにサーバーをセットアップしているので、今度はクライアントをセットアップする方法を学びます。
手順1-現在のプロジェクトフォルダーの外に新しいフォルダーjquery-client-appを作成します
まず、プロジェクトフォルダーの外に jquery-client-app という名前のフォルダーを作成します。
ステップ2-jQuery統合用のHTMLページindexlを作成する
jqueryでクライアントアプリケーションを作成し、両方のメソッドを呼び出します。 以下は、 indexl ファイルのコードです。 indexl ページは、ボタン Greet および SayHello がクリックされると、サーバーにリクエストを送信します。 $ .ajax()関数を使用して非同期リクエストを作成します。
<!DOCTYPE html>
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("#btnSayhello").click(function() {
const name = $("#txtName").val();
console.log(name);
$("#SayhelloDiv")l('loading....');
$.ajax({url: "http://localhost:9000/graphql",
contentType: "application/json",type:'POST',
data: JSON.stringify({ query:`{
sayHello(name:"${name}")}`
}),
success: function(result) {
console.log(JSON.stringify(result))
$("#SayhelloDiv")l("<h1>"+result.data.sayHello +"</h1>");
}
});
});
$("#btnGreet").click(function() {
$("#greetingDiv")l('loading....');
//https://kannan-first-graphql-app.herokuapp.com/graphql
$.ajax({url: "http://localhost:9000/graphql",
contentType: "application/json",
type:'POST',
data: JSON.stringify({
query:`{greeting}`
}),
success: function(result) {
$("#greetingDiv")l("<h1>"+result.data.greeting+"</h1>");
}
});
});
});
</script>
</head>
<body>
<h1>Jquery Client </h1>
<hr/>
<section>
<button id = "btnGreet">Greet</button>
<br/> <br/>
<div id = "greetingDiv"> </div>
</section>
<br/> <br/> <br/>
<hr/>
<section>
Enter a name:<input id = "txtName" type = "text" value = "kannan"/>
<button id = "btnSayhello">SayHello</button>
<div id = "SayhelloDiv"> </div>
</section>
</body>
</html>
ブラウザでこのファイルを開き、ボタンをクリックして応答を確認します。 出力は以下のようになります-
GraphQL-React統合
Reactは、ユーザーインターフェイスを構築するためのJavaScriptライブラリです。 この章では、GraphQLをReactアプリケーションと統合する方法について説明します。
図
Reactプロジェクトをセットアップする最も簡単な方法は、Create React App toolを使用することです。 以降のセクションでは、サーバーとクライアントの両方をセットアップする方法を学習します。
サーバーのセットアップ
サーバーを設定するには、以下の手順に従ってください-
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
*react-server-app* フォルダーを作成します。 ターミナルからディレクトリを「 *react-server-app* 」に変更します。 環境設定の章で説明されている手順3〜5に従います。
ステップ2-スキーマを作成する
プロジェクトフォルダーに schema.graphql ファイルを追加し、 react-server-app に次のコードを追加します-
type Query
{
greeting: String
sayHello(name:String!):String
}
このファイルでは、「greeting」と「sayHello」という2つのクエリが定義されています。 saysayelloクエリは、文字列パラメーターを受け取り、別の文字列を返します。 saysayello()関数のパラメーターがnullではありません。
ステップ3-リゾルバーを作成する
プロジェクトフォルダにファイル resolvers.js を作成し、次のコードを追加します-
const Query =
{
greeting: () => 'Hello GraphQL From finddevguides !!' ,
sayHello:(root,args,context,info) => `Hi ${args.name} GraphQL server says Hello to you!!`
}
module.exports = {Query}
ここでの挨拶と挨拶は2人のリゾルバです。 sayHello resolverでは、nameパラメーターに渡された値はargsを介してアクセスできます。 モジュール外のリゾルバー関数にアクセスするには、module.exportsを使用してQueryオブジェクトをエクスポートする必要があります。
ステップ4-アプリケーションを実行する
server.jsファイルを作成します。 環境設定の章の手順8を参照してください。 ターミナルでコマンド_npm start_を実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
ブラウザを開き、URL http://localhost:9000/graphiql を入力します。 エディタで次のクエリを入力します-
{
greeting,
sayHello(name:"Mohtashim")
}
サーバーからの応答は以下のとおりです-
{
"data": {
"greeting": "Hello GraphQL From finddevguides !!",
"sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
}
}
クライアントのセットアップ
クライアント用の新しいターミナルを開きます。 サーバーアプリケーションは、クライアントアプリケーションを実行する前に実行し続ける必要があります。 Reactアプリケーションはポート番号3000で実行され、サーバーアプリケーションはポート番号9000で実行されます。
ステップ1-Reactプロジェクトhello-world-clientを作成する
クライアント端末で、次のコマンドを入力します-
npx create-react-app hello-world-client
これにより、典型的なリアクションアプリケーションに必要なすべてがインストールされます。 npx ユーティリティと create-react-app ツールは、hello-world-clientという名前のプロジェクトを作成します。 インストールが完了したら、VSCodeでプロジェクトを開きます。
ステップ2-hello-world-clientを開始します
ターミナルの現在のフォルダーパスをhello-world-clientに変更します。 npm startと入力して、プロジェクトを起動します。 これにより、ポート3000で開発サーバーが実行され、ブラウザーが自動的に開き、インデックスページが読み込まれます。
これは、以下のスクリーンショットに示されています-
ステップ3-アプリコンポーネントの変更
srcフォルダー内のApp.jsで、グリーティングをロードする関数とsayHelloメッセージをロードする関数の2つの関数を追加します。
以下は、挨拶のためにGraphQLクエリを送信する「loadGreeting」関数です。
async function loadGreeting() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:'{greeting}'})
})
const rsponseBody = await response.json();
return rsponseBody.data.greeting;
console.log("end of function")
}
以下は、sayHelloのGraphQLクエリを送信する loadSayhello 関数です-
async function loadSayhello(name) {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{sayHello(name:"${name}")}`})
})
}
完全な App.js ファイルを以下に示します-
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
async function loadGreeting() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:'{greeting}'})
})
const rsponseBody = await response.json();
return rsponseBody.data.greeting;
console.log("end of function")
}
async function loadSayhello(name) {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{sayHello(name:"${name}")}`})
})
const rsponseBody = await response.json();
return rsponseBody.data.sayHello;
}
class App extends Component {
constructor(props) {
super(props);
this.state = {greetingMessage:'',sayHelloMessage:'',userName:''}
this.updateName = this.updateName.bind(this);
this.showSayHelloMessage = this.showSayHelloMessage.bind(this);
this.showGreeting = this.showGreeting.bind(this);
}
showGreeting() {
loadGreeting().then(g => this.setState({greetingMessage:g+" :-)"}))
}
showSayHelloMessage() {
const name = this.state.userName;
console.log(name)
loadSayhello(name).then(m => this.setState({sayHelloMessage:m}))
}
updateName(event) {
this.setState({userName:event.target.value})
}
render() {
return (
<div className = "App">
<header className = "App-header">
<img src = {logo} className = "App-logo" alt = "logo"/>
<h1 className = "App-title">Welcome to React</h1>
</header>
<br/><br/>
<section>
<button id = "btnGreet" onClick = {this.showGreeting}>Greet</button>
<br/> <br/>
<div id = "greetingDiv">
<h1>{this.state.greetingMessage}</h1>
</div>
</section>
<hr/>
<section>
Enter a name:<input id = "txtName" type = "text" onChange = {this.updateName}
value = {this.state.userName}/>
<button id = "btnSayhello" onClick = {this.showSayHelloMessage}>SayHello</button>
<br/>
user name is:{this.state.userName} <br/>
<div id = "SayhelloDiv">
<h1>{this.state.sayHelloMessage}</h1>
</div>
</section>
</div>
);
}
}
export default App;
両方のアプリケーションが実行されたら、「挨拶」ボタンをクリックします。 次に、テキストボックスに名前を入力し、sayHelloボタンをクリックします。 出力は以下のようになります-
GraphQL-Apolloクライアント
Apolloサーバーを使用して、サーバー側でgraphql仕様を作成しました。 実稼働対応のGraphQLサーバーをすばやく簡単に構築できます。 次に、クライアント側について理解しましょう。
Apollo Clientは、GraphQLを使用してクライアントアプリケーションを構築する最良の方法です。 クライアントは、開発者がGraphQLでデータを取得するUIを迅速に構築し、JavaScriptフロントエンドで使用できるように設計されています。
Apollo Clientは以下のプラットフォームをサポートしています-
Sr.No. | Platform & Framework |
---|---|
1 |
Javascript React、Angular、Vue、Meteor、Ember |
2 |
WebComponents ポリマー、lit-apollo |
3 |
Native Mobile Javaを備えたネイティブAndroid、Swiftを備えたネイティブiOS |
キャッシングは、Apolloクライアントの主要な機能の1つです。 apollo-boostは、他の多くの依存関係をもたらす便利なパッケージです。
図
私たちは次の手順を使用してクライアントアプリケーションを構築するためにApolloクライアントを使用する方法を見てみましょう-
サーバーのセットアップ
私たちは、サーバーをセットアップするために以下の手順に従う必要があります-
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
フォルダapollo-server-appを作成します。 ターミナルからディレクトリを「 apollo-server-app 」に変更します。 次に、環境設定の章で説明されている手順3〜5を実行します。
ステップ2-スキーマを作成する
プロジェクトフォルダma apollo-server-app に schema.graphql ファイルを追加し、次のコードを追加します-
type Query
{
students:[Student]
}
type Student {
id:ID!
firstName:String
lastName:String
college:College
}
type College {
id:ID!
name:String
location:String
rating:Float
}
ステップ3-リゾルバーを追加する
プロジェクトフォルダにファイル resolvers.js を作成し、次のコードを追加します-
const db = require('./db')
const Query = {
//resolver function for students returns list
students:() => db.students.list(),
}
const Student = {
college:(root) => {
return db.colleges.get(root.collegeId);
}
}
module.exports = {Query,Student}
ステップ4-アプリケーションを実行する
*server.js* ファイルを作成します。 環境設定の章の手順8を参照してください。 ターミナルでコマンド_npm start_を実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
ブラウザを開き、URL http://localhost:9000/graphiql を入力します。 エディターに次のクエリを入力します。
{
students{
id
firstName
college{
name
}
}
}
クエリの応答は以下のとおりです-
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim",
"college": {
"name": "CUSAT"
}
},
{
"id": "S1002",
"firstName": "Kannan",
"college": {
"name": "AMU"
}
},
{
"id": "S1003",
"firstName": "Kiran",
"college": {
"name": "AMU"
}
}
]
}
}
クライアントのセットアップ
クライアント用の新しいターミナルを開きます。 サーバーアプリケーションは、クライアントアプリケーションを実行する前に実行し続ける必要があります。 Reactアプリケーションはポート番号3000で実行され、サーバーアプリケーションはポート番号9000で実行されます。
ステップ1-Reactアプリケーションを作成する
クライアント端末で、次のコマンドを入力します-
npx create-react-app hello-world-client
これにより、典型的なリアクションアプリケーションに必要なすべてがインストールされます。 npxユーティリティとcreate-react-appツールは、 hello-world-client という名前のプロジェクトを作成します。 インストールが完了したら、VSCodeでプロジェクトを開きます。
ステップ2-hello-world-clientを開始します
ターミナルの現在のフォルダーパスを hello-world-client に変更します。 npm startと入力して、プロジェクトを起動します。 これにより、ポート3000で開発サーバーが実行され、ブラウザーが自動的に開き、インデックスページが読み込まれます。
これは、以下のスクリーンショットに示されています-
ステップ3-Apolloクライアントライブラリのインストール
Apolloクライアントをインストールするには、新しいターミナルを開き、現在のプロジェクトフォルダーパスに移動します。 次のコマンドを入力します-
npm install apollo-boost graphql
これにより、クライアント側のgraphqlライブラリとApollo Boostパッケージがダウンロードされます。 これをクロスチェックするには、apollo-boost依存関係にinnpm viewと入力します。 以下に示すように、これには多くの依存関係があります-
{
'apollo-cache': '^1.1.15',
'apollo-cache-inmemory': '^1.2.8',
'apollo-client': '^2.4.0',
'apollo-link': '^1.0.6',
'apollo-link-error': '^1.0.3',
'apollo-link-http': '^1.3.1',
'apollo-link-state': '^0.4.0',
'graphql-tag': '^2.4.2'
}
Apollo-Clientライブラリがインストールされていることがはっきりとわかります。
手順4-index.jsファイルでアプリコンポーネントを変更する
Apollo Clientを使用すると、フェッチAPIを使用せずにサーバーを直接呼び出すことができます。 また、逆ティック表記で作成された文字列にクエリと突然変異を埋め込まないでください。 これは、 gql 関数がクエリを直接解析するためです。 つまり、プログラマはGraphiQLツールでクエリを作成するときと同じ方法でクエリを直接作成できます。 gql は、back tick表記で書かれたテンプレート文字列をgraphqlクエリオブジェクトに解析するタグ関数です。 Apolloクライアントクエリメソッドはプロミスを返します。
次のコードスニペットは、Apolloクライアントをインポートする方法を示しています-
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
const endPointUrl = 'http://localhost:9000/graphql'
const client = new ApolloClient({
link: new HttpLink({uri:endPointUrl}),
cache:new InMemoryCache()
});
前の章では、HTTPリクエストにフェッチAPIを使用する方法について説明しました。 次のコードは、 gql 関数の使用方法を示しています。 loadStudentsAsync 関数は、graphqlクライアントを使用してサーバーに照会します。
async function loadStudentsAsync() {
const query = gql`
{
students{
id
firstName
lastName
college{
name
}
}
}`
const {data} = await client.query({query}) ;
return data.students;
}
*index.js* を *src* フォルダーに保持し、indexlをパブリックフォルダーに保持するだけです。自動生成される他のすべてのファイルは削除できます。
ディレクトリ構造は以下のとおりです-
hello-world-client/
-->node_modules
-->public
indexl
-->src
index.js
-->package.json
以下は、reactアプリケーションの index.js です-
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
//apollo client
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
import gql from 'graphql-tag'
const endPointUrl = 'http://localhost:9000/graphql'
const client = new ApolloClient({
link: new HttpLink({uri:endPointUrl}),
cache:new InMemoryCache()
});
async function loadStudentsAsync() {
const query = gql`
{
students{
id
firstName
lastName
college{
name
}
}
}
`
const {data} = await client.query({query}) ;
return data.students;
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
students:[]
}
this.studentTemplate = [];
}
async loadStudents() {
const studentData = await loadStudentsAsync();
this.setState({
students: studentData
})
console.log("loadStudents")
}
render() {
return(
<div>
<input type = "button" value = "loadStudents" onClick = {this.loadStudents.bind(this)}/>
<div>
<br/>
<hr/>
<table border = "3">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>college Name</td>
</tr>
</thead>
<tbody>
{
this.state.students.map(s => {
return (
<tr key = {s.id}>
<td>
{s.firstName}
</td>
<td>
{s.lastName}
</td>
<td>
{s.college.name}
</td>
</tr>
)
})
}
</tbody>
</table>
</div>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
次に示すように、loadStudentsボタンをクリックすると、反応アプリケーションはGraphQLサーバーから生徒をロードします-
GraphQL-認証クライアント
認証は、ユーザーまたはプロセスのIDを検証するプロセスまたはアクションです。 アプリケーションがユーザーを認証し、匿名ユーザーがデータを使用できないようにすることが重要です。 このセクションでは、GraphQLクライアントを認証する方法を学びます。
Express JWT
この例では、jQueryを使用してクライアントアプリケーションを作成します。 リクエストを認証するには、サーバー側でon express-jwt モジュールを使用します。
「express-jwt」モジュールは、JWTトークンを使用してHTTP要求を認証できるミドルウェアです。 JSON Web Token(JWT)は、ログインしているユーザーを識別する長い文字列です。
ユーザーが正常にログインすると、サーバーはJWTトークンを生成します。 このトークンは、ログを明確に識別します。 言い換えれば、トークンはユーザーの身元の表現です。 そのため、次回、クライアントがサーバーにアクセスすると、必要なリソースを取得するためにこのトークンを提示する必要があります。 クライアントは、モバイルアプリケーションまたはWebアプリケーションのいずれかです。
図
この図を理解するために、段階的な手順に従います。
サーバーのセットアップ
以下は、サーバーをセットアップするための手順です-
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
フォルダ auth-server-app を作成します。 端末からディレクトリを「 auth-server-app 」に変更します。 環境設定の章で説明されている手順3〜5に従います。
ステップ2-スキーマを作成する
プロジェクトフォルダma auth-server-app に schema.graphql ファイルを追加し、次のコードを追加します-
type Query
{
greetingWithAuth:String
}
ステップ3-リゾルバーを追加する
プロジェクトフォルダにファイル resolvers.js を作成し、次のコードを追加します-
リゾルバは、GraphQLのコンテキストオブジェクトで認証済みのユーザーオブジェクトが利用可能かどうかを確認します。 認証されたユーザーが利用できない場合、例外が発生します。
const db = require('./db')
const Query = {
greetingWithAuth:(root,args,context,info) => {
//check if the context.user is null
if (!context.user) {
throw new Error('Unauthorized');
}
return "Hello from finddevguides, welcome back : "+context.user.firstName;
}
}
module.exports = {Query}
ステップ4-Server.jsファイルを作成する
認証ミドルウェアは、JSON Web Tokenを使用して発信者を認証します。 認証用のURLは http://localhost:9000/login です。
これは後処理です。 ユーザーは、バックエンドから検証されるメールとパスワードを送信する必要があります。 有効なトークンが「jwt.sign」メソッドを使用して生成される場合、クライアントは後続のリクエストのためにヘッダーでこれを送信する必要があります。
トークンが有効な場合、「req.user」は、承認およびアクセス制御のために後のミドルウェアによって使用されるようにデコードされたJSONオブジェクトで設定されます。
次のコードは、リクエストを認証するために、jsonwebtokenとexpress-jwtの2つのモジュールを使用します-
- ユーザーが greet ボタンをクリックすると、/graphqlルートのリクエストが発行されます。 ユーザーが認証されていない場合、ユーザー自身の認証を求められます。
- ユーザーには、メールIDとパスワードを受け入れるフォームが表示されます。 この例では、/loginルートがユーザーの認証を担当します。 */loginルートは、ユーザーが提供した資格情報と一致するデータベースがあるかどうかを確認します。
- 資格情報が無効な場合、HTTP 401例外がユーザーに返されます。
- 資格情報が有効な場合、サーバーによってトークンが生成されます。 このトークンは、ユーザーへの応答の一部として送信されます。 これは、jwt.sign関数によって行われます。
const expressJwt = require('express-jwt');
const jwt = require('jsonwebtoken');
//private key
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
app.post('/login', (req, res) => {
const {email, password} = req.body;
//check database
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
//generate a token based on private key, token doesn't have an expiry
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
リクエストごとに、app.use()関数が呼び出されます。 これにより、expressJWTミドルウェアが呼び出されます。 このミドルウェアはJSON Web Tokenをデコードします。 トークンに保存されているユーザーIDが取得され、プロパティオブジェクトユーザーとしてリクエストオブジェクトに保存されます。
//decodes the JWT and stores in request object
app.use(expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
GraphQLコンテキスト内でユーザープロパティを使用できるようにするために、このプロパティは以下に示すように context オブジェクトに割り当てられます-
//Make req.user available to GraphQL context
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));
現在のフォルダパスに server.js を作成します。 完全なserver.jsファイルは次のとおりです-
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const expressJwt = require('express-jwt');//auth
const jwt = require('jsonwebtoken');//auth
const db = require('./db');
var port = process.env.PORT || 9000
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
const app = express();
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
app.use(cors(), bodyParser.json(), expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user && db.students.get(req.user.sub)}
})));
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
//authenticate students
app.post('/login', (req, res) => {
const email = req.body.email;
const password = req.body.password;
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
app.listen(port, () => console.info(`Server started on port ${port}`));
ステップ5-アプリケーションを実行する
ターミナルでコマンド_npm_ startを実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
ブラウザを開き、URL http://localhost:9000/graphiql を入力します。 エディタで次のクエリを入力します-
{
greetingWithAuth
}
以下の応答では、認証されたユーザーではないためエラーが発生しました。
{
"data": {
"greetingWithAuth": null
},
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"greetingWithAuth"
]
}
]
}
次のセクションでは、認証するクライアントアプリケーションを作成します。
JQueryクライアントのセットアップ
クライアントアプリケーションでは、スキーマ greetingWithAuth を呼び出す[あいさつ]ボタンが提供されます。 ログインせずにボタンをクリックすると、以下のエラーメッセージが表示されます-
データベースで利用可能なユーザーでログインすると、次の画面が表示されます-
あいさつ*にアクセスするには、まず以下のようにURL *http://localhost:9000/login routeにアクセスする必要があります。
応答には、サーバーから生成されたトークンが含まれます。
$.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus')
l("authenticated successfully")
.css({"color":"green",'font-weight':'bold'});
$("#greetingDiv")l('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
ログインに成功すると、以下に示すように_greetingWithAuth_スキーマにアクセスできます。 「bearer」トークンを使用した後続のすべてのリクエストには、「AuthorizationHeader」が必要です。
{
url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken}, type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}`
}
以下はindexlのコードです-
<!DOCTYPE html>
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
let loginToken = "";
$("#btnGreet").click(function() {
$.ajax({url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken},
type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}` }),
success: function(result) {
$("#greetingDiv")l("<h1>"+result.data.greetingWithAuth+"</h1>")
},
error:function(jQxhr,error) {
if(jQxhr.status == 401) {
$("#greetingDiv")l('please authenticate first!!')
.css({"color":"red",'font-weight':'bold'})
return;
}
$("#greetingDiv")l('error').css("color","red");
}
});
});
$('#btnAuthenticate').click(function() {
var email = $("#txtEmail").val();
var password = $("#txtPwd").val();
if(email && password) {
$.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus')
l("authenticated successfully")
.css({"color":"green",'font-weight':'bold'});
$("#greetingDiv")l('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
}else alert("email and pwd empty")
})
});
</script>
</head>
<body>
<h1> GraphQL Authentication </h1>
<hr/>
<section>
<button id = "btnGreet">Greet</button>
<br/> <br/>
<div id = "greetingDiv"></div>
</section>
<br/> <br/> <br/>
<hr/>
<section id = "LoginSection">
<header>
<h2>*Login first to access greeting </h2>
</header>
<input type = "text" value = "[email protected]" placeholder = "enter email" id = "txtEmail"/>
<br/>
<input type = "password" value = "pass123" placeholder = "enter password" id = "txtPwd"/>
<br/>
<input type = "button" id = "btnAuthenticate" value = "Login"/>
<p id = "authStatus"></p>
</section>
</body>
</html>
GraphQL-キャッシング
キャッシングは、「キャッシュ」と呼ばれる一時記憶領域にデータを保存するプロセスです。 最近アクセスしたページに戻ると、ブラウザは元のサーバーではなくキャッシュからこれらのファイルを取得できます。 これにより、時間とネットワークが追加のトラフィックの負担から節約されます。
GraphQLと対話するクライアントアプリケーションは、データを最後にキャッシュする責任があります。 このパターンの1つとして考えられるのは、likeidなどのフィールドをグローバルに一意の識別子として予約することです。
InMemoryキャッシュ
InMemoryCacheは、Reduxなどの他のライブラリを使用せずに、GraphQLクライアントアプリケーションで一般的に使用される正規化されたデータストアです。
ApolloClientでInMemoryCacheを使用するためのサンプルコードは以下のとおりです-
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
const cache = new InMemoryCache();
const client = new ApolloClient({
link: new HttpLink(),
cache
});
InMemoryCacheコンストラクターは、プロパティを含むオプションの構成オブジェクトを使用して、キャッシュをカスタマイズします。
Sr.No. | Parameter & Description |
---|---|
1 |
addTypename __typenameをドキュメントに追加するかどうかを決定するブール値(デフォルト:true) |
2 |
dataIdFromObject データオブジェクトを受け取り、ストア内のデータを正規化するときに使用される一意の識別子を返す関数 |
3 |
fragmentMatcher デフォルトでは、InMemoryCacheはヒューリスティックフラグメントマッチャーを使用します |
4 |
cacheRedirects 要求が発生する前に、クエリをキャッシュ内の別のエントリにリダイレクトする関数のマップ。 |
図
ReactJSで、ホームタブ用と学生用の2つのタブを持つ単一ページのアプリケーションを作成します。 学生タブは、GraphQLサーバーAPIからデータをロードします。 ユーザーが[ホーム]タブから[学生]タブに移動すると、アプリケーションは_students_データを照会します。 結果のデータはアプリケーションによってキャッシュされます。
また、 getTime フィールドを使用してサーバー時間をクエリし、ページがキャッシュされているかどうかを確認します。 キャッシュからデータが返された場合、ページにはサーバーに送信された最初のリクエストの時間が表示されます。 データがサーバーに対して行われた新しい要求の結果である場合、サーバーからの最新の時刻が常に表示されます。
サーバーのセットアップ
以下は、サーバーをセットアップするための手順です-
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
フォルダ cache-server-app を作成します。 ターミナルからディレクトリを「 cache-server-app 」に変更します。 環境設定の章で説明されている手順3〜5に従います。
ステップ2-スキーマを作成する
プロジェクトフォルダ cache-server-app に schema.graphql ファイルを追加し、次のコードを追加します-
type Query {
students:[Student]
getTime:String
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
}
ステップ3-リゾルバーを追加する
プロジェクトフォルダにファイルresolvers.jsを作成し、次のコードを追加します-
const db = require('./db')
const Query = {
students:() => db.students.list(),
getTime:() => {
const today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
return `${h}:${m}:${s}`;
}
}
module.exports = {Query}
ステップ4-アプリケーションを実行する
server.jsファイルを作成します。 環境設定の章の手順8を参照してください。 ターミナルでコマンド_npm start_を実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
ブラウザを開き、URL http://localhost:9000/graphiql を入力します。 エディタで次のクエリを入力します-
{
getTime
students {
id
firstName
}
}
サンプル応答には、生徒の名前とサーバー時間が表示されます。
{
"data": {
"getTime": "22:18:42",
"students": [
{
"id": "S1001",
"firstName": "Mohtashim"
},
{
"id": "S1002",
"firstName": "Kannan"
},
{
"id": "S1003",
"firstName": "Kiran"
}
]
}
}
ReactJSクライアントのセットアップ
クライアント用の新しいターミナルを開きます。 サーバーアプリケーションは、クライアントアプリケーションを実行する前に実行し続ける必要があります。 Reactアプリケーションはポート番号3000で実行され、サーバーアプリケーションはポート番号9000で実行されます。
ステップ1-Reactアプリケーションを作成する
クライアント端末で、次のコマンドを入力します-
npx create-react-app hello-world-client
これにより、典型的なリアクションアプリケーションに必要なすべてがインストールされます。 * npxユーティリティ*および create-react-app ツールは、hello-world-clientという名前のプロジェクトを作成します。 インストールが完了したら、VSCodeでプロジェクトを開きます。
次のコマンドを使用して、react用のルーターモジュールをインストールします- npm install react-router-dom 。
ステップ2-hello-world-clientを開始します
ターミナルの現在のフォルダーパスをhello-world-clientに変更します。 npm startと入力して、プロジェクトを起動します。 これにより、ポート3000で開発サーバーが実行され、ブラウザーが自動的に開き、インデックスページが読み込まれます。
これは、以下のスクリーンショットに示されています-
ステップ3-Apolloクライアントライブラリのインストール
Apolloクライアントをインストールするには、新しいターミナルを開き、現在のプロジェクトフォルダーパスに移動します。 次のコマンドを入力します-
npm install apollo-boost graphql
これにより、クライアント側のgraphqlライブラリとApollo Boostパッケージがダウンロードされます。 これをクロス検証するには、npm view apollo-boostの依存関係を入力します。 以下に示すように、これには多くの依存関係があります-
{
'apollo-cache': '^1.1.15',
'apollo-cache-inmemory': '^1.2.8',
'apollo-client': '^2.4.0',
'apollo-link': '^1.0.6',
'apollo-link-error': '^1.0.3',
'apollo-link-http': '^1.3.1',
'apollo-link-state': '^0.4.0',
'graphql-tag': '^2.4.2'
}
apollo-clientライブラリがインストールされていることがはっきりとわかります。
手順4-index.jsファイルでアプリコンポーネントを変更する
単純な反応アプリケーションの場合、 index.js を src フォルダーに保存し、 indexl をパブリックフォルダーに保存するだけです。自動生成される他のすべてのファイルは削除できます。
ディレクトリ構造は以下のとおりです-
hello-world-client/
-->node_modules
-->public
indexl
-->src
index.js
students.js
-->package.json
学生コンポーネントを含む追加のファイルstudent.jsを追加します。 学生の詳細は、学生コンポーネントを通じて取得されます。 Appコンポーネントでは、HashRouterを使用しています。
以下は、reactアプリケーションの index.js です-
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {HashRouter, Route, Link} from 'react-router-dom'
//components
import Students from './students'
class App extends Component {
render() {
return(
<div><h1>Home !!</h1>
<h2>Welcome to React Application !! </h2>
</div>
)
}
}
function getTime() {
var d = new Date();
return d.getHours()+":"+d.getMinutes()+":"+d.getSeconds()
}
const routes = <HashRouter>
<div>
<h4>Time from react app:{getTime()}</h4>
<header>
<h1> <Link to="/">Home</Link>
<Link to = "/students">Students</Link> </h1>
</header>
<Route exact path = "/students" component = {Students}></Route>
<Route exact path = "/" component = {App}></Route>
</div>
</HashRouter>
ReactDOM.render(routes, document.querySelector("#root"))
ステップ5-Students.jsでコンポーネントの生徒を編集する
学生コンポーネントでは、次の2つのアプローチを使用してデータを読み込みます-
- * Fetch API(loadStudents_noCache)*-これは、学生タブをクリックするたびに新しいリクエストをトリガーします。
- * Apollo Client(loadWithApolloclient)*-これはキャッシュからデータを取得します。
サーバーから学生と時間を照会する関数 loadWithApolloclient を追加します。 この関数はキャッシュを有効にします。 ここでは、gql関数を使用してクエリを解析します。
async loadWithApolloclient() {
const query = gql`{
getTime
students {
id
firstName
}
}`;
const {data} = await client.query({query})
return data;
}
*Fetch API* は、リソースを取得するためのシンプルなインターフェイスです。 Fetchを使用すると、古いXMLHttpRequestを使用するよりも、Web要求を作成して応答を処理しやすくなります。 次の方法は、フェッチAPIを使用してデータを直接ロードすることを示しています-
async loadStudents_noCache() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{
getTime
students {
id
firstName
}
}`})
})
const rsponseBody = await response.json();
return rsponseBody.data;
}
StudentsComponentのコンストラクターで、 loadWithApolloClient メソッドを呼び出します。 完全な Student.js ファイルは以下です-
import React, {Component} from 'react';
import { Link} from 'react-router-dom'
//Apollo Client
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
import gql from 'graphql-tag'
const client = new ApolloClient({
link: new HttpLink({uri:`http://localhost:9000/graphql`}),
cache:new InMemoryCache()
})
class Students extends Component {
constructor(props) {
super(props);
this.state = {
students:[{id:1,firstName:'test'}],
serverTime:''
}
this.loadWithApolloclient().then(data => {
this.setState({
students:data.students,
serverTime:data.getTime
})
})
}
async loadStudents_noCache() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{
getTime
students {
id
firstName
}
}`})
})
const rsponseBody = await response.json();
return rsponseBody.data;
}
async loadWithApolloclient() {
console.log("inside apollo client function")
const query = gql`{
getTime
students {
id
firstName
}
}`;
const {data} = await client.query({query})
return data;
}
render() {
return(
<div>
<h3>Time from GraphQL server :{this.state.serverTime}</h3>
<p>Following Students Found </p>
<div>
<ul>
{
this.state.students.map(s => {
return(
<li key = {s.id}>
{s.firstName}
</li>
)
})
}
</ul>
</div>
</div>
)
}
}
export default Students
ステップ6-_npm start_を使用してReactアプリケーションを実行する
[ホーム]タブから[学生]タブに切り替えることで、反応アプリケーションをテストできます。 学生タブにサーバーからのデータがロードされると。 データをキャッシュします。 自宅から生徒タブに複数回切り替えることでテストできます。 出力は以下のようになります-
URL、 http://localhost:3000/#/students を入力して最初に生徒のページを読み込んだ場合、反応アプリとGraphQLの読み込み時間がほぼ同じであることがわかります。 その後、ホームビューに切り替えてGraphQLサーバーに戻っても、時間は変わりません。 これは、データがキャッシュされていることを示しています。
ステップ7-loadWithApolloclient呼び出しをloadStudents_noCacheに変更します
StudentComponentのコンストラクターでloadメソッドを loadStudents_noCache に変更すると、出力はデータをキャッシュしません。 これは、キャッシュと非キャッシュの違いを示しています。
this.loadStudents_noCache().then(data => {
this.setState({
students:data.students,
serverTime:data.getTime
})
})
loadWithApolloclientを使用したReactアプリケーションの出力
上記の出力から、タブ間を切り替えると、graphqlサーバーからの時間が常に最新であり、データがキャッシュされないことがわかります。