Oops!!

プログラミングとかのラフなブログ

GraphQL NexusにObjectの配列を渡す

GraphQL NexusにObjectの配列を渡す

クライアント側からソートのデータを渡してもらうことによって、バックエンドではそれを元にしてデータを渡すだけの状況を作りたいと思います。

// schema.ts
export const UserObject = objectType({
  name: 'User',
  definition(t) {
    t.string('name')
    t.string('email')
    t.string('role')
  }
})

export const UserQuery = extendType({
  type: 'Query',
  definition(t) {
    t.list.field('users', {
      type: UserObject,
      args: {
        orderBy: /*...*/,
      },
      async resolve(_root, args, { prisma }) {
        // これがやりたい
        //[{ name: 'desc' }, { role: 'asc' }]
        console.log(args.orderBy)
        return prisma.user.findMany({
          orderBy: args.orderBy
        })
      },
    })
  },
})

ちょっと見にくいですが、args.orderByに[{ name: 'desc' }, { role: 'asc' }]を渡したいという感じです。

enumTypeとinputObjectTypeを使って定義する

enumTypeでvalueに'desc' | 'asc'のみを許可するようにします。

inputはinputObjectTypeで定義することでNexusの方で生成してくれます。 このOrderByの定義はnullを許容しているのでどちらもプロパティもなくても問題ありません。

export const OrderByMembers = enumType({
  name: 'OrderByMembers',
  members: ['desc', 'asc'],
})

export const OrderByType = inputObjectType({
  name: 'OrderByType',
  definition(t) {
    t.field('name', {
      type: OrderByMembers
    })
    t.field('role', {
      type: OrderByMembers
    })
  }
})

これを配列で渡せるようにしていきます。

export const UserQuery = extendType({
  type: 'Query',
  definition(t) {
    t.list.field('users', {
      type: UserObject,
      args: {
        // inputObjectTypeで定義したものをlist()で追加
        orderBy: list('OrderBy'),
      },
      async resolve(_root, args, { prisma }) {
        console.log(args.orderBy)
        return prisma.user.findMany({
          orderBy: args.orderBy
        })
      },
    })
  },
})

クライアントのQueryについて

クライアントはApollo Clientを使用しています。

生成されたschemaを見るとinput OrderBy { ... }があると思うので、配列で投げれるように[OrderBy]を記述します。

自分はTypeScriptの要領でOrderBy[]と書いてハマってました。

import { gql, useQuery } from '@apollo/client'

const QUERY = gql`
  query($orderBy: [OrderBy]) {
    users(orderBy: $orderBy) {
      name
      email
      role
    }
  }
`

const { data } = useQuery<{ users: User[] }>(QUERY, {
  variables: {
    orderBy: [{ name: 'desc' }]
  }
})

今回はシンプルなorderByを想定しましたが、実際は{ members: { posts: { count: 'desc' } } }みたいな記述も出てくるので、少し悩んでいます。

ソートや絞り込みなどクライアントからパラメーターを渡して使用する頻度は多いと思うけど、Nexusの定義方法についての詳細な記述は少なかったです。(各々ドキュメントに書いてあって組み合わせるだけだから理解できるよねって感じだとは思います。)

プロフィール画像

すずき ゆうた

愛知県でフリーランスのフロントエンド・エンジニアをしています。Reactを用いた開発が得意です。 他にもプロジェクトマネジメントや組織マネジメントも行ってきました。エビデンスのない事でも自分の経験から書いていくので話半分くらいでお願いします。