Open7

GraphQL

bz0bz0

https://qiita.com/NagaokaKenichi/items/d341dc092012e05d6606

エクスクラメーションマーク(!マーク)の意味

エクスクラメーションマークがついているフィールドは、そのフィールドがnullになることがないことを意味

LaravelでのGraphQL開発

前提

下記ライブラリを利用
https://github.com/nuwave/lighthouse

playgroundで動作確認
https://localhost/graphql-playground

公式マニュアル:
https://lighthouse-php.com

ページネーションのカスタム

query {
  TQuery(first:10, page:1) {
    data{
      title
      genre
      writer
    }
    paginatorInfo{
      total
    }
  }
}

src/graphql/schema.graphql

type Query {
    TQuery: [Test!]! @paginate(builder: "App\\GraphQL\\Queries\\TestQuery")
}

type Test {
    title: String
    writer: String
    genre: Int
}
namespace App\GraphQL\Queries;

use Illuminate\Support\Facades\DB;

class TestQuery
{
    public function __invoke($_, array $args)
    {
        return DB::table('test1')
            ->join('test2',[['test1.id', '=', 'test2.test1_id']])
            ->orderBy('test2.created_at', 'asc');
    }
}

カラム単位にメソッドからデータ取得

https://stackoverflow.com/questions/67113127/how-to-properly-serve-custom-queries-with-method-directive-in-lighthouse-php

app/GraphQL/Queries/xxx.php

namespace App\GraphQL\Queries;

class xxx
{
    public function __invoke($_, array $args)
    {
        return $this;
    }

    public function test()
    {
        return 1111;
    }
}

graphql/schema.graphql

type Query {
    xxx: xxx
}

type xxx {
    test: Int @method
}
bz0bz0
mutation {
  createPost(input: { user_id: 1, content: "aaaaaaaaaa" }) {
    user_id
    content
  }
}

mutation {
  updatePost(id: 1, input: { user_id: 1, content: "bbbb" }) {
    user_id
    content
  }
}
query {
  posts(first:10, page:1) {
    data{
      user_id
      content
    }
    paginatorInfo{
      total
    }
  }
}

query {
  posts(first:10, page:1) {
    data{
      user_id
      content
      user {
        github_id
        avatar_url
        bio
      }
    }
    paginatorInfo{
      total
    }
  }
}
bz0bz0
  • 認証
    • 認証されていないアクセスからすべてのフィールドを保護したい場合
      • Laravelデフォルトで用意されているauth:api
      • userテーブルのapi_tokenとAuthorizationヘッダを元に認証
bz0bz0

github認証ログイン(通常の画面遷移の場合)

web.php

Route::get('/home', function () {
    echo 'homeページ!!!!!!';
    $user = Auth::user();
    var_dump($user);
})->middleware('auth');

Route::get('/login', function () {
    echo 'loginページ!!!!!!';
})->name('login');

Route::get('/login/github', function () {
    return Socialite::driver('github')
        ->scopes(['read:user', 'public_repo'])
        ->redirect();
});

Route::get('/auth/github/callback', function () {
    $githubUser = Socialite::driver('github')->user();

    $user = User::where('github_id', $githubUser->id)->first();

    if ($user) {
        $user->update([
            'name' => $githubUser->name,
            'email' => $githubUser->email,
            'bio' => $githubUser->user['bio'],
            'avatar_url' => $githubUser->user['avatar_url'],
            'github_token' => $githubUser->token,
            'github_refresh_token' => $githubUser->refreshToken,
        ]); //プロフィール変更したら更新されるようにするため
    } else {
        $user = User::create([
            'name' => $githubUser->name,
            'email' => $githubUser->email,
            'provider' => Provider::GITHUB,
            'bio' => $githubUser->user['bio'],
            'avatar_url' => $githubUser->user['avatar_url'],
            'github_id' => $githubUser->id,
            'github_token' => $githubUser->token,
            'github_refresh_token' => $githubUser->refreshToken,
        ]);
    }

    Auth::login($user);
});
bz0bz0

https://apollographql-jp.com/tutorial/mutations/

https://qiita.com/suzuki0430/items/1812e600797bba661cef

headerのauthorization指定

const client = new ApolloClient({
  cache,
  link: new HttpLink({
    uri: 'http://localhost:4000/graphql',
    headers: {
      authorization: localStorage.getItem('token'),
    },
  }),
});

更新処理

  const [updatePost, mutationResult] = useMutation<
    UpdatePostData,
    PostInputType
  >(UPDATE_POST);

useMutaionの型

useMutation<
  TData, // mutationが返すデータの型
  TError, // mutationが返すエラーの型
  TVariables, // muatate関数の変数の型
  TContext // onMutate内でセットされるコンテキストの型
>
  const handleSave = async () => {
    await updatePost({
      variables: {
        params: {
          id: parseInt(post.id),
          title: post.title,
          body: post.body,
        },
      },
    });

    mutationError
      ? alert(`Error: ${JSON.stringify(mutationError)}`)
      : setMessage('Successfully saved');
  };
bz0bz0

useMutation
新規投稿した後に、一覧を更新することが簡単にできる

  const { loading, error, data, fetchMore, refetch } = useQuery<PostsData>(POSTS_QUERY, {
    variables: {
      first: 100,
      page: 1
    }
  });
  const [createPost, { loading_cP, error_cP }] = useMutation(CREATE_POST,{
    onCompleted() {
      refetch();
    },
  });