GithubHelp home page GithubHelp logo

Comments (12)

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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>
    );
  });
}
  • 追加や削除のときは明示的にコードを書かなきゃいけない

参照

from sns-merng.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

ポート使用されてるエラー

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

HTTPヘッダとは?

  • クライアントとサーバー間でHTTP通信(リクエスト・レスポンス)をする際に、HTTPヘッダというところに追加情報を付与する
  • 例えば認証情報(トークンとか)を付与することができる
  • 参照

from sns-merng.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

追記: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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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/writeQueryreadFragment/writeFragmentcache.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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.