前回は、オブジェクトを作成し、GraphQL でオブジェクトの一覧や、特定のオブジェクトを取得しました。

今回は、オブジェクト同士で関連付けをします。

コードは、前回のコードを使います。

const { ApolloServer, gql } = require("apollo-server")

const books = [
  {
    id: 1,
    title: "オズの魔法使",
    author: "ライマン・フランク・ボーム",
  },
  {
    id: 2,
    title: "風と共に去りぬ",
    author: "マーガレット・ミッチェル",
  },
]

const typeDefs = gql`
  type Query {
    books: [Book!]!
    book(id: Int!): Book
  }

  type Book {
    id: Int!
    title: String!
    author: String!
  }
`

const resolvers = {
  Query: {
    books: () => books,
    book: (parent, args, context) => {
      const bookId = args.id
      const book = books.find(book => book.id === bookId)
      if (!book) return null
      return book
    },
  },
}

const server = new ApolloServer({
  typeDefs,
  resolvers,
})

server.listen().then(({ url }) => {
  console.log("🚀  Server ready at " + url)
})

カテゴリを作成する

まずは、本と関連付けさせるために、カテゴリを作成します。

const categories = [
  {
    id: "literature",
    name: "文学",
  },
  {
    id: "self-help",
    name: "自己啓発",
  },
]

今のところ、自己啓発の本がないので、自己啓発の本を追加します。

const books = [
  {
    id: 1,
    title: "オズの魔法使",
    author: "ライマン・フランク・ボーム",
  },
  {
    id: 2,
    title: "風と共に去りぬ",
    author: "マーガレット・ミッチェル",
  },
  {
    id: 3,
    title: "人を動かす",
    author: "D・カーネギー",
  },
]

Book と同様に、typeDefsにも Category を作成します。

const typeDefs = gql`
  type Query {
    books: [Book!]!
    book(id: Int!): Book
    categories: [Category!]!
    category(id: ID!): Category
  }

  type Book {
    id: Int!
    title: String!
    author: String!
  }

  type Category {
    id: ID!
    name: String!
  }
`

リゾルバーも book を参考にし、category を作成します。

const resolvers = {
  Query: {
    books: () => books,
    book: (parent, args, context) => {
      const bookId = args.id
      const book = books.find(book => book.id === bookId)
      if (!book) return null
      return book
    },
    categories: () => categories,
    category: (parent, args, context) => {
      const categoryId = args.id
      const category = categories.find(category => category.id === categoryId)
      if (!category) return null
      return category
    },
  },
}

では、ブラウザで確認します。

『+』ボタンを押して、新しいクエリを作成します。

image2

新しいクエリで、query の後に、クエリのタイトルを作成することができます。

今回は、『Categories』にします。

すると、上部のタブや実行ボタンも『Categories』へ変わります。

image3

categories に『id』と『name』を設定します。

image4

『Categories』ボタンをクリックしてみると、

image5

カテゴリ一覧が表示されました。

次に、特定のカテゴリを表示させてみます。

新しいクエリを作ります。

名前は、『Category』にします。

image6

category と入力すると、自動で、Variables も設定されます。

『id』と『name』を設定します。

image7

Variables に、『literature 』を指定します。

image8

『Category』ボタンをクリックすると、

image9

『文学』のカテゴリが表示されました。

カテゴリの一覧を表示する

カテゴリの一覧を指定すると、カテゴリに合致する本の一覧が表示される様にします。

まずは、books データに、それぞれカテゴリの ID を設定します。

const books = [
  {
    id: 1,
    title: "オズの魔法使",
    author: "ライマン・フランク・ボーム",
    categoryId: "literature",
  },
  {
    id: 2,
    title: "風と共に去りぬ",
    author: "マーガレット・ミッチェル",
    categoryId: "literature",
  },
  {
    id: 3,
    title: "人を動かす",
    author: "D・カーネギー",
    categoryId: "self-help",
  },
]

typeDefs内にある、Category クエリに、booksを追加します。

type Category {
  id: ID!
  name: String!
  books: [Book!]!
}

Query リゾルバーの下に、Category リゾルバーを作成します。

const resolvers = {
  Query: {
    books: () => books,
    book: (parent, args, context) => {
      const bookId = args.id
      const book = books.find(book => book.id === bookId)
      if (!book) return null
      return book
    },
    categories: () => categories,
    category: (parent, args, context) => {
      const categoryId = args.id
      const category = categories.find(category => category.id === categoryId)
      if (!category) return null
      return category
    },
  },
  Category: {},
}

取得する内容は、books なので、Category 内に books を作成します。

また、Query の book や category と同様に、(parent, args, context)を作成します。

Category: {
  books: (parent, args, context) => {

  },
},

今回は、Book と Category が親子関係になっているので、parentを使います。

試しに、console.logで確認します。

Category: {
  books: (parent, args, context) => {
    console.log(parent);
  },
},

ブラウザで Categories タブを開きます。

name の下に、books を指定します。

image10

『Categories』ボタンをクリックします。

image11

image12

ブラウザはエラーになりますが、console.log では category の『id』と『name』が取得できています。

では、parentidを指定します。

Category: {
  books: (parent, args, context) => {
    const id = parent.id;
  },
},

books のcategoryIdと合致するidを取得するときは、filterを使います。

Category: {
  books: (parent, args, context) => {
    const id = parent.id;
    return books.filter((book) => book.categoryId === id);
  },
},

では、ブラウザで確認します。

image13

『Categories』をクリックすると、

image14

カテゴリとカテゴリに合致する本の一覧を取得することができました。

本の内容に、カテゴリ名を取得する

今度は、本の内容に、カテゴリ名を取得します。

typeDefsの Book クエリに、category を追加します。

type Book {
  id: Int!
  title: String!
  author: String!
  category: Category!
}

リゾルバーの Category と同様に、Book を作成します。

const resolvers = {
  Query: {
    books: () => books,
    book: (parent, args, context) => {
      const bookId = args.id
      const book = books.find(book => book.id === bookId)
      if (!book) return null
      return book
    },
    categories: () => categories,
    category: (parent, args, context) => {
      const categoryId = args.id
      const category = categories.find(category => category.id === categoryId)
      if (!category) return null
      return category
    },
  },
  Category: {
    books: (parent, args, context) => {
      const id = parent.id
      return books.filter(book => book.categoryId === id)
    },
  },
  Book: {
    category: (parent, args, context) => {
      const categoryId = parent.categoryId
    },
  },
}

単一のデータを取得するときは、findを使います。

Book: {
  category: (parent, args, context) => {
    const categoryId = parent.categoryId;
    return categories.find((category) => category.id === categoryId);
  },
},

では、ブラウザで確認します。

ExampleQuery タブをクリックします。

ExampleQuery を Book に変えておきます。

タイトルの下に、categoryを設定します。

image15

『Book』をクリックすると、

image16

本の内容の中に、カテゴリ名も追加されました。

ブログ一覧