ApolloのTutorialをやる
2021/5/27にやった
別projectに書いてたやつを移してきた

ApolloのTutorialをやる
GraphQLよくわからんので触ってみる
server側のコードはどれぐらい書き換える必要があるのか
web/RNで共通の実装を使えるのか
clientはどういう実装になるのか
Entityとか
既存の実装からの移行はどれぐらい大変か
SpaceXの宇宙行き便へ搭乗予約をするためのアプリケーションを作る
GraphQL Serverは、
SQLiteとREST
を中継する
cloneしたやつにはstartとfinalディレクトリがある
finalは完成版。お手本
startに実装を追加していく。最終的にfinalになる
この構成良いな

server/client両方書く
実装場所は別々
Apollo Srverをセットアップする
apollo-server
と graphql
をinstall
Schemaを構築する
ここにSchemaを書く
jsconst typeDefs = gql`
# Your schema will go here
`;
なんかのVSCode拡張入れないと色が付かない

Launch
は、1つのロケット発射情報的なやつ
こういうのをObject Typeというらしい
普通のtsの文脈におけるそれのことか?
gql type Launch {
id: ID!
site: String
mission: Mission
rocket: Rocket
isBooked: Boolean!
}
!
があるものがnon Null
null許容の方がデフォなんだ..

gql type User {
id: ID!
email: String!
trips: [Launch]!
token: String
}
[]
は配列
gql type Mission {
name: String
missionPatch(size: PatchSize): String
}
enum PatchSize {
SMALL
LARGE
}
missionPathは引数を取る
SMALLかLARGE
Query
type
gqltype Query {
launches: [Launch]!
launch(id: ID!): Launch
me: User
}
見た目は同じだが、 Query
という名のSchemaは扱いが特殊
1つ1つのfiledが、client目線のqueryになる
この例なら、clientは例えば me
という問い合わせができる
あれ、なんか思ってたのと違うな?

server sideで用意したAPI endpointじゃないと問い合わせできないの
#??なんかclientで適当にgraph qlのコード書いたらその形式のデータが自由に取れるものだと思ってたんだが
できる

こんな感じで書く
queryquery Query {
me {
id
email
trips {
site
mission {
missionPatch
name
}
}
}
}
Mutation
type
これも特殊
gqltype Mutation {
bookTrips(launchIds: [ID]!): TripUpdateResponse!
cancelTrip(launchId: ID!): TripUpdateResponse!
login(email: String): User
}
データ変更するquery的なやつ
各fieldがendpointっぽい感じにならしい
Queryとか、Mutationって、fieldがめちゃくちゃ増えそうな気がするが、同名(QueryやMutation)で複数の型定義できるのか?
npm startでよく見る画面が出る
データソースをGraphQL APIにつなぎこむ
DataSource
というclassを使う
RESTとDBをこれにつなげる
RESTと繋ぐ
apollo-datasource-rest
の RESTDataSource
classをextendsして使う
追加の設定無しでcacheしてくれる
this.get
の基盤になるやつか
baseURL= https://google.com
なら、 this.get('hoge')
としたら、 http://google.com/hoge
からfetchする感じ
上で定義した Query
の各fieldに対応する実装を LaunchAPI
classのmethodとして実装していく
RESTと繋ぐってそっちか〜

そらそうか。
client→graphQL→ ここ
→なんかのAPI server
ここ
の部分を作っている
既存API Serverに対してGraphQLを接続しているので、こういう実装が必要になる
今作っているLaunchAPI内のmethodで、
RESTのresponse
を、 さっき定義したGraphQL Schema
に変換する実装を手動で書く
ってことは、API Serverは今後も作り続けないといけないの
#??何も嬉しくなっていない
たぶんこれはあとから説明される「DBとの接続」で解決されるはず
運営し続けたときの修正箇所メッチャ多くないか?
こういう実装のおかげでGraphQLとAPI Serverが疎結合になる
これ普通に外部APIサービス使っているって話だった

忘れてた
https://api.spacexdata.com/v2/
は外部のサービスだ
これって結局、client目線で新しいAPI必要になったらServerも修正しないといけないのか
#??場合に依るか
DBと接続する
SQLiteとそのORMを使っている
UserAPI classはORMでSQLiteの中身をゴニョる実装を書いている
別にORMが必須というわけでもないだろう

各methodに適合するSQLをそこに書けば同じことはできるはず
2つのDataSourceとApolloServerを接続する
今まで書いていたものは読み取り専用ってことか

対象はRESTとDB
ちがう、queryを使って読み取りもできていない
わからんくなった、Data Sourceってなんだ
#??今まで書いていたものをresolversと呼ぶと思ってたがそういうわけではないんだな

QueryのResolverを書く
これでようやくqueryで読み取りができるようになる
Resolver
GraphQL Schemaの1filedごとにfetchする関数を定義する?
だるそー

これらの関数(resolver)は、Shcmeaで定義した型のデータか、Promiseを返す
各resolverのinterfaceは決まっている
e.g. fieldName: (parent, args, context, info) => data;
引数部分の型が決まっている
object型には入れ子関係があるが、親のresolverのほうが子より先に呼ばれる
Query
のfieldと名前を合わせて定義する
js Query: {
launches: (_, __, { dataSources }) =>
dataSources.launchAPI.getAllLaunches(),
launch: (_, { id }, { dataSources }) =>
dataSources.launchAPI.getLaunchById({ launchId: id }),
me: (_, __, { dataSources }) => dataSources.userAPI.findOrCreateUser()
}
これ別にQueryに限らず他のSchemaに対しても定義しないといけないらしい
でも全部やる必要はない
みづれー

あ、でもこれでresolver完成7日
ここに出てくる getAllLaunches
とかはさっきのDataSource定義したやつ
たぶん
contextを仲介してアクセスする
resolverを薄く保つのがベスプラらしい
resolverは定義してなくてもdefaultのものがある程度がんばってくれるらしい
どういうロジックかは知らん
allで返すのではなくpagenationできる
LaunchConnectionを使う
cursorは現在のindex
なぜString?
mutationのResolverを書く
ApploServerのcontextに指定する
この関数はclientがserverに送信するたびに呼ばれる
認証とかに使う
読んでない
clientを見ていく
clientはtsなんだ

うわ、5を読んでないと無理やんけ
動かさずに読むだけにしよう
めちゃくちゃ雑に読んでる
Componentごとかなんかでquery書いて、useQueryで呼べばデータが取れる
ノリはSWRとかに近い
data, loading, errorとかも返してくれる
clientはメッチャ楽になるな

まさにGraphQLという感じ
確かにうまくやればReduxとかは不要になりそう
もういいかな
残りは読んでない