前回作成したデータが index.js に全て納まっていますので、見通しをよくするために、ファイルを再編成します。

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

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

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

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!
    category: Category!
  }

  type Category {
    id: ID!
    name: String!
    books: [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
      return categories.find(category => category.id === categoryId)
    },
  },
}

データを再編成する

まずは、データを別ファイルにします。

database フォルダを作成し、books.js と categories.js を作成します。

index.js の books データをコピーして、books.js に貼り付けます。

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

books が外部で使えるように、exportsを設定します。

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

books と同様に、categories も categories.js に設定します。

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

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

image2

実行すると、

image3

正常に機能しています。

スキーマを再編成する

次は、スキーマを別ファイルにします。

schema.js を作成します。

index.js のtypeDefsをコピーして、schema.js の中に貼り付けます。

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!
    category: Category!
  }

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

apollo-server から gql をインポートします。

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

typeDefsが外部で使えるように、exportsを設定します。

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

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

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

index.js で、gqlが不要になったので、インポートから除外します。

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

typeDefsをインポートします。

const { typeDefs } = require("./schema")

では、機能しているかブラウザで確認します。

image4

実行してもエラーになりません。

リゾルバーを再構築する

リゾルバーを別ファイルにします。

resolver フォルダを作成し、Query.js、Category.js、Book.js を作成します。

index.js のresolvers内にあるQueryをコピーして、Query.js に貼り付けます。

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;
  },
},

Query が外部で使えるように、exports を使用します。

また、Query の後の『:』を『=』へ変えます。

さらに、最後の『,』を『;』へ変えます。

exports.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
  },
}

bookscategoriesのデータをインポートします。

const { books } = require("../database/books")
const { categories } = require("../database/categories")

Category.js と Book.js も同様に、設定します。

resolvers/Category.js

const { books } = require("../database/books")

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

resolvers/Book.js

const { categories } = require("../database/categories")

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

index.js で設定したbookscategoriesのインポートは、必要ないので削除します。

また、resolversも削除します。

index.js で、各リゾルバーをインポートします。

const { Query } = require("./resolvers/Query")
const { Category } = require("./resolvers/Category")
const { Book } = require("./resolvers/Book")

servers のなかの resolvers にQueryCategoryBookを設定します。

const server = new ApolloServer({
  typeDefs,
  resolvers: {
    Query,
    Category,
    Book,
  },
})

一通り完成したので、動作確認を行います。

image5

GraphQL を実行してもエラーにならず、機能しています。

リゾルバーに必要なデータを渡す様にする

今のところ、各リゾルバー内で、直接データをインポートしています。

データのインポートを index.js で一元管理します。

index.js でbookscategoriesのデータをインポートします。

const { books } = require("./database/books")
const { categories } = require("./database/categories")

serverresolversの下に、contextを追加します。

const server = new ApolloServer({
  typeDefs,
  resolvers: {
    Query,
    Category,
    Book,
  },
  context: {},
})

context の中に、bookscategoriesを設定します。

context: {
  books,
  categories,
},

これで、books と categories を自由に取り出せる様になりました。

resolvers フォルダの Query.js を開きます。

booksのインポートは必要ないので、削除します。

Query の books に、parent, args, contextを設定します。

contextの中を、先程 index.js で設定した{books}に変えます。

books: (parent, args, { books }) => books,

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

image6

エラーにはならず、機能しています。

他のcontextも書き換えましょう。

categoriesのインポートも必要ないので、削除します。

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

const bookId = args;const categoryId = args.id;{id}へ書き換えることができます。

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

では、確認します。

image7

問題なく、機能しています。

理ゾルバーの残りも修正します。

resolvers/Category.js

exports.Category = {
  books: ({ id }, args, { books }) => {
    return books.filter(book => book.categoryId === id)
  },
}

resolvers/Book.js

exports.Book = {
  category: ({ categoryId }, args, { categories }) => {
    return categories.find(category => category.id === categoryId)
  },
}

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

image8

GraphQL が機能しました。

これで、コード全体の見通しがよくなりました。

ブログ一覧