Next.js と Google Books APIs を使って、簡単な書籍検索アプリを作っていきたいと思います。
完成イメージ
今回作成する書籍検索アプリの完成イメージは、次のとおりです。
スポンサーリンク
Next.js とは
Next.js は Reactをベースにしたフロントエンドフレームワークです。ゼロコンフィグで使えるファイルベースルーティングや、表示速度を高速化するサーバーサイドレンダリングなど、規模が大きい React アプリを作る時に便利な機能が詰まっています。
さらに、Next.js にはバックエンド側の機能も備わっているため、フロントエンドと同じプロジェクトで Node.js を使ってバックエンド側の処理を作ることもできます。
Google Books APIs とは
Google Books APIs は、その名のとおり Google が提供している書籍検索 API のひとつです。登録や、API キーのなどの認証が必要なく、プログラミングを学習する時などに便利なライブラリです。
https://developers.google.com/books
プロジェクトの作成
適当なプロジェクト名で、Next.js のプロジェクトを作成します。(今回は「sample-books」という名前でプロジェクトを作成しました)
また、言語は TypeScirpt を使用します。
npx create-react-app sample-books --template typescript
スポンサーリンク
バックエンド側の API の作成
まずは、バックエンド側の処理を作ります。
いきなりフロント側から Google Books APIs にアクセスしてもいいですが、アプリで使わない JSON のタグも多く、それのせいでフロント側の処理が煩雑になるため、バックエンド側で API を実行し、必要な情報のみに絞った JSON データに整形し、それをフロント側に渡すようにします。
pages/api/
の下に books.ts
を作成し、 Google Books APIs からデータを取得し、JSONデータを整形後、フロントに返す処理を書きます。
import type { NextApiRequest, NextApiResponse } from 'next'
// google books api から取得した情報の簡易版インタフェース
export interface Book {
id: string,
title: string,
description: string,
pageCount: number | null,
image: string,
mainCategory: string,
categories: string[],
}
/**
* Google Books API で鬼滅関連の書籍を検索する関数
* [GET]/api/books
*
* @param req リクエスト
* @param res レスポンス
*/
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Book[]>
) {
let q = req.query.q || ""
q = Array.isArray(q) ? q[0] : q
const data = await getData(q)
res.status(200).json(data)
}
/**
* Google Books API の実行と取得結果(JSON)の整形を行う関数
*
* @param q 検索クエリ
* @returns 見つかった書籍のリスト
*/
export async function getData(query: string) : Promise<Book[]> {
const response = await fetch("https://www.googleapis.com/books/v1/volumes?q=" + encodeURIComponent(query))
const jsonData = await response.json()
return jsonData.items.map((elem: any) => {
return {
id: elem.id,
title: elem.volumeInfo.title,
description: elem.volumeInfo?.description,
pageCount: elem?.pageCount,
image: elem.volumeInfo?.imageLinks?.thumbnail,
mainCategory: elem.volumeInfo?.mainCategory,
categories: elem.volumeInfo?.categories,
}
})
}
Google Books APIs から返ってくる JSON データの詳細は、公式の次のページを見てください。
Google Books APIs Reference volumes
フロント側の作成
書籍検索ページの作成
pages/
の下に sample.tsx
を作成し、検索ボックスと、検索結果を表示するリストを作る。また、onClickSearch
関数では、検索ボタンがクリックされた時に、上で作成したバックエンド側の API を呼び出している。
import BookItem from '../components/BookItem';
import type { NextPage } from 'next';
import { SyntheticEvent, useEffect, useState } from 'react';
import styles from '../styles/Sample.module.css';
import { Book } from './api/books';
const Sample: NextPage = () => {
const [query, setQuery] = useState(""); // 検索条件
const [items, setItems] = useState(new Array<Book>()); // 書籍リスト
/**
* 検索ボタンをクリックした時の処理
* サーバーサイドのAPIを呼び出し、書籍情報の検索を行う
*/
const onClickSearch = async (e: SyntheticEvent) => {
const response = await fetch("/api/books?q=" + encodeURIComponent(query))
setItems(await response.json());
};
// Render
return (
<div className={styles.container}>
<input type="text" value={query} onChange={e => setQuery(e.target.value)}></input>
<button onClick={onClickSearch}>検索</button>
<ul className={styles.books}>
{items.map((item, index) => (
<li key={index}>
<BookItem book={item}></BookItem>
</li>
))}
</ul>
</div>
)
}
export default Sample
BookItem コンポーネントの作成
components/BookItem
の下に BookItem.tsx
というファイルを作成する。
import { Book } from 'pages/api/books';
import styles from './BookItem.module.css'
type AppProps = { book: Book };
const BookItem = ({book}: AppProps) => {
return (
<div className={styles.book_grid_wrapper}>
<>
{book.image ?
<img className={styles.book_grid_image} src={book.image}/> :
<div>No Image</div>
}
</>
<div>
<div className={styles.book_grid_title}>{book.title}</div>
<div>
{(book.categories || []).map((tab) => {
<div>{tab}</div>
})}
</div>
</div>
<div className={styles.book_grid_description}>
<div className={styles.inner}>
{book.description}
</div>
</div>
</div>
)
}
export default BookItem;
同フォルダに BookItem.module.css
も作成し、スタイルを指定する。
.book_grid_wrapper {
display: grid;
grid-template-columns: 200px 2fr 1fr;
grid-auto-rows: minmax(5rem, auto);
}
.book_grid_image {
align-self: start;
}
.book_grid_title {
align-self: start;
}
.book_grid_description {
align-self: start;
}
.book_grid_description .inner {
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
スポンサーリンク
まとめ
かなりザックリな説明になったが、これで一通りの実装は完成である。実行して動きを確かめてみてください。
0 件のコメント:
コメントを投稿