初めてのGraphQL 読書メモ
https://scrapbox.io/files/64b5d8fe9e7f8a001ce18fac.png
そもそも
GraphQLとは、APIへの問い合わせをする言語。
sample
メリット1:過剰な取得を防ぐことができる
返却する値を意識する必要はあるが、API側で工夫をしなくても取得する値を最小限にすることができる。
Seliarizerで関連モデルの情報を全て取ってしまう、みたいなのが防げそうだと思った。
ただ意識するといっても、REST APIで細かくjsonを作るみたいなのとは全然違うので非常に楽。
メリット2: エンドポイントの管理が不要
/graphqlで取得ができる
デメリット
書籍には書いていないが、エラーハンドリングの実装は自分でやる必要があった。
ステータスコードを正しいものにすることはできないので、どうするか考える。
グラフ理論
GraphQLのグラフ理論に関して、有向グラフ、無向グラフのそれぞれわかりやすい説明
および図を出力して欲しいです。初心者に分かりやすいように説明してください。
code: text
まず、グラフ理論について基本的な説明から始めましょう。グラフ理論は数学の一分野で、物事の関係性を表現するためのツールとして使用されます。グラフ理論では、「グラフ」と呼ばれる概念を用いて、物事の間の関係を視覚的に表現します。
「グラフ」は、「ノード」(または「頂点」)と「エッジ」(または「辺」)と呼ばれる2つの主要な要素で構成されます。
ノード:個々のアイテムやエンティティを表現します。例えば、人、場所、物など。
エッジ:ノード間の関係や接続を表現します。例えば、友人関係、道路、フライト経路など。
そして、グラフは主に2つのタイプに分けられます:「有向グラフ」と「無向グラフ」。
有向グラフ:エッジには方向性があり、ノード間の関係が一方向であることを示します。例えば、Twitterのフォロー関係は有向グラフで表現できます。あなたが誰かをフォローしていても、その人があなたをフォローしているとは限りません。
無向グラフ:エッジには方向性がなく、ノード間の関係が双方向であることを示します。例えば、Facebookの友人関係は無向グラフで表現できます。あなたが誰かと友人である場合、その人もまたあなたと友人です。
それぞれのグラフを図で表現すると以下のようになります:
有向グラフ:
css
Copy code
A --> B
^ |
| v
D <-- C
この図では、AからBへ、BからCへ、CからDへ、そしてDからAへというようにエッジが方向を持っています。
無向グラフ:
css
Copy code
A -- B
| |
D -- C
この図では、全てのノードが互いに接続されており、エッジには方向性がありません。
次数:ノードに接続されているエッジの数
それぞれのノードの次数が奇数の場合、全ての橋(エッジ)を1回だけ渡る方法がない
例えば、1->2->3->4みたいなグラフの場合、2,3のノードに関して次数は奇数なので、一筆書できる
これは面白い
📝 あとはこれ読み終わったら、チュートリアルもやった方が良さそうな気配
Subscription
まだ実装したことはないが、ソケット通信でデータの変更を監視するようなことができる。
試せる
fragment サンプルコード
code: gpt4.gql
# フラグメントの定義
fragment UserInfo on User {
id
name
email
}
# フラグメントを使用したクエリ
query getUsers {
users {
...UserInfo
}
}
query getUserById($id: ID!) {
user(id: $id) {
...UserInfo
}
}
この例では、UserInfoという名前のフラグメントを定義しています。このフラグメントはUserタイプに対して使用でき、id、name、emailというフィールドを取得します。その後、getUsersとgetUserByIdという2つのクエリでこのフラグメントを使用しています。...UserInfoという記述でフラグメントを適用しています。これにより、クエリの記述が簡潔になり、再利用性が向上します。
ユニオン型の場合
code: gpt-4.gql
# ユニオン型の定義
union SearchResult = User | Post
type User {
id: ID!
name: String!
email: String!
}
type Post {
id: ID!
title: String!
content: String!
}
# ユニオン型を使用したクエリ
query search($text: String!) {
search(text: $text) {
... on User {
id
name
email
}
... on Post {
id
title
content
}
}
}
この例では、SearchResultという名前のユニオン型を定義しています。このユニオン型はUser型またはPost型のどちらかを表します。 その後、searchというクエリでこのユニオン型を使用しています。... on Userと... on Postという記述で、ユニオン型がどの型を表しているかによって異なるフィールドを取得しています。これにより、異なる型のデータを一つのクエリで取得することができます。
あとは同じfieldを別名で取得もできる。エイリアスという機能
code:graphql
{
firstName: name
secondName: name
}
イントロスペクション
スキーマ定義を取得できる。クライアントのツールで簡単に表示できてたのも多分これのおかげかな。
スキーマ
GraphQLの方を定義できる。SDL。
スカラー型
組み込みの型。Stringなど。
非null修飾子とリスト
code: GPT-4
Type : 基本型。nullまたは該当型の値が返ります。
Type! : 常に該当型の値を返し、nullは返りません。
Type : リスト型。nullまたは該当型のリストが返ります。リストの要素はnullになり得ます。 Type! : 要素が非nullのリスト。リスト自体はnullかもしれないが、リストが存在する場合は要素は必ず該当型となります。 Type! : 必ず該当型のリストを返しますが、リストの要素はnullになり得ます。 Type!! : 常に該当型の非null要素のリストを返します。リスト自体も要素もnullにはなりません。 非null修飾子を扱うことで、1:多などの実現もできる(P71)
引数が多くなってきた時に行う実装:input型
よく見るやつ。
code: graphql
input UserInfoInput {
name: String!
email: String!
age: Int
}
type Mutation {
createUser(user: UserInfoInput!): User!
}
type User {
id: ID!
name: String!
email: String!
age: Int
}
インプットはこんな感じになる。
code: json
{
"user": {
"name": "John Doe",
"email": "john@example.com",
"age": 30
}
}
返却の際の型
code: graphql
type AuthPayload {
user: User!
token: String!
}
type Mutation {
githubAuth(code: String): AuthPayload!
}
サブスクリプション型なんかもあるので、実際に使ってみるのが良さそう。
GraphQLサーバーの実装
実際に手を動かしてみる。
やる。一旦
--legacy-peer-depsをつけた。
→そもそもからフォルダでスタートするの勘違い。
空フォルダから作成...
code: js
const typeDefs = `
type Query {
totalPhotos: Int!
}
type Mutation {
postPhoto(name: String! description: String): Boolean!
}
`
こんな感じでスキーマを定義する。Mutationには対応するリゾルバも存在する
リゾルバの中でQueryもMutationも実行できる
code: js
const resolvers = {
Query: {
totalPhotos: () => photos.length
},
Mutation: {
postPhoto(parent, args) {
photos.push(args)
return true
}
}
}
code:graphql
mutation newPhoto($name: String!, $description: String) {
postPhoto(name: $name, description: $description)
}
サーバー側の処理をしてる間はphotos[]もデータ保持できていた。
型を返す場合は選択セットを定義する
code: graphql
postPhoto(name: $name, description: $description) {
id
name
description // ここら辺のこと
}
Apollo Serverのリゾルバファンクションの仕様に注意
引用
Before we can start writing resolvers, we need to learn more about what a resolver function looks like. Resolver functions accept four arguments:
fieldName: (parent, args, context, info) => data;
parent: 親 resolver から受け取ったオブジェクト。
args: この field に対して渡された引数。
context: GraphQL operation の resolver 全体で共有されるオブジェクト。このチュートリアルでは認証情報やデータソースを context で共有している。
info: 実行したオペレーションに関する状態等の詳細情報。通常は用いられないがよりアドバンスなケースにおいて使われることが多い。
だいぶ忘れていたので復習し、5章からやり直す。
リゾルバ
特定フィールドの値を返す関数のことを指す。graphql-rubyだとfieldがそうかな?
動作させてみた
実行する場合はこれを使う
code:sample.gql
mutation newPhoto($name: String!, $description: String) {
postPhoto(name: $name, description: $description) {
id
name
description
}
}
# ここのクエリ名はなんでもいい
query listPhotos {
allPhotos {
description
id
url
}
}