Comments (12)
GraphQLの初歩
- メリット
- データのクエリをシンプルに欲しい物だけ実行できる
- コードの書き方
- スキーマ(どのフィールドをクエリするか、そのクエリはどんな型か)
- リゾルバ関数(実際のデータの操作)
使い方
const { ApolloServer, gql } = require('apollo-server');
//スキーマの定義
const schema = gql`
type Query{
sayHi: String
}
`;
//リゾルバ関数の定義
const resolvers = {
Query: {
sayHi: () => "Hello World!";
}
};
//ApolloServerインスタンスの作成
const server = new ApolloServer({
schema,
resolvers
})
//サーバー立ち上げ
server.listen({port: 5000});
参照
from sns-merng.
mongooseの使い方
スキーマ・モデル・ドキュメント
// mongooseではスキーマからすべてが始まる
// スキーマの定義
const kittySchema = new mongoose.Schema({
name: String
});
//スキーマをモデルにコンパイル
//Kittenという名前で参照する
const Kitten = mongoose.model('Kitten', kittySchema);
//モデルを使ってドキュメントを作成
//ドキュメントは、スキーマで定義したプロパティや動作を持つ
const silence = new Kitten({ name: 'Silence' });
console.log(silence.name); // 'Silence'
クエリ
//クエリはモデルを介して行われる
//nameがGhostのKittenを1つ取ってくる、そしてそれをqueryに格納
const query = Kitten.findOne({ 'name': 'Ghost' });
//データ保存はドキュメントを介して行われる
const fluffy = new Kitten({ name: 'fluffy' });
fluffy.save();
スキーマの定義の仕方について補足(リレーションについて)
//以下は同じ
const kittySchema = new mongoose.Schema({
name: String
});
const kittySchema = new mongoose.Schema({
name: {type: String}
});
//ref属性について
//refを使うとリレーションを表現することができる
const personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
参照
from sns-merng.
GraphQLでのAuthentication(認証)
- Authenticationとは
- ユーザーがログインしているかどうかを判定
- そのユーザーがどのユーザーであるかをチェック
- Authorization in GraphQL
context
オブジェクトを作成しそこに、認証情報などを格納する
//この関数は、userフィールドを持ったcontextオブジェクトを作成している
//これはコンストラクタで定義しておく
context: ({ req }) => {
// get the user token from the headers
const token = req.headers.authentication || '';
// try to retrieve a user with the token
const user = getUser(token);
// optionally block the user
// we could also check user roles/permissions here
if (!user) throw new AuthorizationError('you must be logged in');
// add the user to the context
return { user };
}
//こんな感じで取り出して操作できる
users: (root, args, context) => {
// In this case, we'll pretend there is no data when
// we're not logged in. Another option would be to
// throw an error.
if (!context.user) return [];
return ['bob', 'jake'];
}
from sns-merng.
Subscriptionについて
- Subscriptionとは
- 特定のサーバ側イベントが発生するたびに結果を更新する読み取り操作
Apollo-ServerでのSubscriptionのやり方
// スキーマの定義は同じ
type Subscription {
postCreated: Post
}
// リゾルバ関数の定義
// リゾルバ関数はsubscribe関数でなくてはならない
// そしてsubscribe関数はAsyncIteratorタイプを返さなくてはならない
const resolvers = {
Subscription: {
subscribe: () => pubsub.asyncIterator('POST_CREATED')
}
}
// PubSubクラス
// Apollo Serverはpub/subモデルを使用してサブスクリプションを更新するイベントを追跡する
const { PubSub } = require('apollo-server');
const pubsub = new PubSub();
// publishメソッドでイベントを追加
// 第1引数でどのイベントに追加するか
// 第2引数はデータ
pubsub.publish('POST_CREATED', {
postCreated: {
author: 'Ali Baba',
comment: 'Open sesame'
}
});
// イベントをlistenする
pubsub.asyncIterator(['POST_CREATED']);
参照
from sns-merng.
Apollo Clientの設定
- フロントエンドとバックエンドのつなぎこみ
//@apollo/clientはセットアップに必要なものが全て含まれてる
$ npm install @apollo/client graphql
//クライアントを作成
import { ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
uri: 'https://hogehoge.com',
cache: new InMemoryCache()
});
//これで準備完了
import React from 'react';
import { render } from 'react-dom';
import { ApolloProvider } from '@apollo/client';
//Apollo Providerでアプリをwrapする
//clientとreactを接続する役割
function App() {
return (
<ApolloProvider client={client}>
<div>
<h2>My first Apollo app 🚀</h2>
</div>
</ApolloProvider>
);
}
render(<App />, document.getElementById('root'));
//useQueryを使ってデータのリクエストを行う
import { useQuery, gql } from '@apollo/client';
//GraphQL Queryの定義
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "USD") {
currency
rate
}
}
`;
function ExchangeRates() {
//データが無事返ってきたらdata変数に格納される
const { loading, error, data } = useQuery(EXCHANGE_RATES);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return data.rates.map(({ currency, rate }) => (
<div key={currency}>
<p>
{currency}: {rate}
</p>
</div>
));
}
参照
from sns-merng.
useMutationのやり方(useQueryも大体同じ)
import { gql, useMutation } from '@apollo/client';
//GraphQLのクエリ文を書く
//このクエリはスキーマ通りに書かないといけない
//例えばStringはダメ、定義通りString!にする
const ADD_TODO = gql`
mutation AddTodo($type: String!) {
addTodo(type: $type) {
id
type
}
}
`;
function AddTodo() {
let input;
//useMutationの返り値はタプル
//1つ目はmutationを実行する関数
//2つ目は「結果」オブジェクト、その中にはloading、errorの状態、value(mutationの返り)とかが含まれる
const [addTodo, { data }] = useMutation(ADD_TODO);
return (
<div>
<form
onSubmit={e => {
e.preventDefault();
//variablesはmutationに渡す変数
addTodo({ variables: { type: input.value } });
input.value = '';
}}
>
<input
ref={node => {
input = node;
}}
/>
<button type="submit">Add Todo</button>
</form>
</div>
);
}
const [addUser, { loading }] = useMutation(REGISTER_USER, {
//updateはmutationを実行したあとにcacheを更新する関数
update(_, result){
props.history.push('/');
},
//onErrorでエラー処理
onError(err){
setErrors(err.graphQLErrors[0].extensions.exception.errors);
},
//ここで変数代入するの???
variables: values
});
参照
from sns-merng.
cache(キャッシュ)とは
- 一時的に保存されるデータ
- ウェブページの情報などを保存しておくことで、再度ページに訪れたときに表示時間が短縮される
- ネットワークリクエストの回数を減らすことができる
- Cookieとは異なる
- cacheを書き換えることで、表示コンテンツを変更することができる
Apolloでのmutation
-
updateのときは明示的にcacheを更新する必要ない
If a mutation updates a single existing entity, Apollo Client can automatically update that entity's value in its cache when the mutation returns. To do so, the mutation must return the id of the modified entity, along with the values of the fields that were modified.
const UPDATE_TODO = gql`
mutation UpdateTodo($id: String!, $type: String!) {
updateTodo(id: $id, type: $type) {
id
type
}
}
`;
function Todos() {
const [updateTodo] = useMutation(UPDATE_TODO);
return data.todos.map(({ id, type }) => {
let input;
return (
<div key={id}>
<p>{type}</p>
<form
onSubmit={e => {
e.preventDefault();
updateTodo({ variables: { id, type: input.value } });
input.value = '';
}}
>
<input
ref={node => {
input = node;
}}
/>
<button type="submit">Update Todo</button>
</form>
</div>
);
});
}
- 追加や削除のときは明示的にコードを書かなきゃいけない
参照
- Reading and writing data to the cache(Apollo Docs)
- Mutations - Update data with the useMutation hook
- Apolloのキャッシュ更新入門 writeQuery / cache.modify / 自動
from sns-merng.
ポート使用されてるエラー
Error: listen EADDRINUSE: address already in use :::5000
ポート5000がすでに使われているというエラー
まず何で使われているのかをチェックlsof -i
コマンド
% lsof -i :5000
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 90236 yuyafurusawa 32u IPv6 0x67d6ac7c1270551d 0t0 TCP *:commplex-main (LISTEN)
このプロセスを削除する
kill -9 90236
from sns-merng.
HTTPヘッダとは?
- クライアントとサーバー間でHTTP通信(リクエスト・レスポンス)をする際に、HTTPヘッダというところに追加情報を付与する
- 例えば認証情報(トークンとか)を付与することができる
- 参照
from sns-merng.
追記:mongoDBへの接続
- スキーマの定義の際にcollectionを指定することができる
// スキーマの定義
const kittySchema = new mongoose.Schema({
name: String
}, {
// ここで接続するcollectionを指定する
collection: 'kitties'
});
// モデルを作成
const Kitten = mongoose.model('Kitten', kittySchema);
//モデルを使ってドキュメントを作成
const silence = new Kitten({ name: 'Silence' });
// 'Ghost'という名前のKittenを
// kittiesというcollectionから探してくる!!!
const query = Kitten.findOne({ 'name': 'Ghost' });
参照
from sns-merng.
ApolloのQueryでのcache
- Apollo ClientではデフォルトでuseQueryすると自動的にcacheを保存しcacheからQueryを行う。
- これは
cache-first
のfetch policyである - cacheを優先するということはネットワークへのリクエストを最小化するので、無駄な通信や表示時間の短縮につながる
- しかし一方で古いcacheが残っていると古い情報をfetchしてしまうことになる
- これは
- もちろんfetch policyは変更できる
- 例えば
no-cache
とするとcacheの保存はしない(なので毎回ネットワークにリクエストする) cache-and-network
とするとcacheとネットワークリクエストからの結果を比較する
- 例えば
参照
from sns-merng.
ApolloでMutationしたあとにlocal dataをupdateする
「mutationを行う=back-endデータを更新する」ということなので、localにキャッシュされたdataを更新したいはず。
例えばtodoリストにitemを追加したら、そのitemもリストに更新したい。
方法①:Queryをrefetchする
シンプルな方法だが、この方法ではネットワークリクエストを発生させてしまう
// mutationの後にrefetchを行う
const [addTodo, { data, loading, error }] = useMutation(ADD_TODO, {
refetchQueries: [
'GetComments' // 以前行ったクエリの名前
],
});
方法②:cacheを直接updateする
ネットワークリクエストを発生させないが、非常に複雑な方法(mutationが複雑化するに従い複雑性が増す)
readQuery
/writeQuery
、readFragment
/writeFragment
、cache.modify
などのAPIを使うことによってcacheを直接操作することができる
//cache.modifyとwriteFragmentを使ってcacheを直接update
const [addTodo] = useMutation(ADD_TODO, {
update(cache, { data: { addTodo } }) {
cache.modify({
fields: {
todos(existingTodos = []) {
const newTodoRef = cache.writeFragment({
data: addTodo,
fragment: gql`
fragment NewTodo on Todo {
id
type
}
`
});
return [...existingTodos, newTodoRef];
}
}
});
}
});
cacheをupdateメソッドの中で更新すると、UIも更新される
Any changes you make to cached data inside of an
update
function are automatically broadcast to queries that are listening for changes to that data. Consequently, your application's UI will update to reflect these updated cached values.
参照
from sns-merng.
Related Issues (3)
- GraphQLのこと HOT 2
- フロントデザインエンジニアリングのこと HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sns-merng.