【GraphQL】1つにまとまっているファイルの構造を再編成する
GraphQL

【GraphQL】1つにまとまっているファイルの構造を再編成する

作成日:2021年11月15日
更新日:2022年02月17日

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

graphql-category

【GraphQL】オブジェクト同士を関連付けする

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 に貼り付けます。

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を設定します。

js
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 に設定します。

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

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

image2

実行すると、

image3

正常に機能しています。

スキーマを再編成する

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

schema.js を作成します。

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

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 をインポートします。

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

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

js
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が不要になったので、インポートから除外します。

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

typeDefsをインポートします。

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

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

image4

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

リゾルバーを再構築する

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

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

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

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 の後の『:』を『=』へ変えます。

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

js
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のデータをインポートします。

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

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

resolvers/Category.js

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

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 で、各リゾルバーをインポートします。

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

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

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

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

image5

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

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

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

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

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

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

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

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

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

js
context: {
books,
categories,
},

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

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

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

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

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

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

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

image6

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

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

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

js
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}へ書き換えることができます。

js
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

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

resolvers/Book.js

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

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

image8

GraphQL が機能しました。

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

© 2024あずきぱんウェブスタジオ