この記事はLCL Advent Calendar 2020 - 6日目です。
ユーザに見えるところの開発が好きなモバイルアプリエンジニアの山下です。
業務ではモバイルアプリ以外にバックエンドやインフラを広く浅く担当していますが、チームの技術スキルが上がると共にキャッチアップする量が増えていき限界を感じつつあります(汗)最近は後者の比率も多く、その反動で個人的にwebサービスを作りたい思いが芽生えてきたので自粛期間中に流行のNext.jsを少し触っていました。
モバイルアプリのようにビルドを待つこともなければ、TypeScriptを使えばRailsのように型で消耗することもないので開発効率が良いですし、Vercelを使えば簡単に無料でホスティングしてくれるので最高の開発体験に感動しています。
とはいえ、生きたサイトを作るとなるとバックエンド(APIやDB)を用意する必要がありますよね。ラクをしようとAWS Amplifyを試してみたもののDynamoDBの扱いに苦戦して(というかこれで消耗したくなくて)挫折しました...。
AWS AmplifyはRDS(Aurora)やSSRに対応してない訳ではないですが、調べると痒いところだらけな雰囲気を感じるのでいい感じに統合されることを期待してもう暫く様子見し、その間にバックエンドが要らない手軽なサイトを作ろうと思い、こんなものを作ってみました。
Remote 🏠 Sale|Amazonレビュー★4以上のリモートワークが捗る製品情報をお届け
イチペラのAmazonリンクが並べてあるだけのサイトです。もう少しちゃんとしたものを作るつもりが、チュートリアルにも満たないサイトになってしまいました(汗)
まあ折角なのでどのように実装したかを簡単に紹介していきます。Next.jsの中身については薄くなってしまいますが、アプリ作成からデプロイまでの雰囲気は掴んで頂けるかと思います。
私のような初学者でも分かりやすいようにスクショ多めで「データ準備編」、「サイト公開編」、「Next.js活用編」の三部構成でお届けします。
材料
- Next.js(with TypeScript)
- Chakra UI:UIコンポーネントライブラリ
- Product Advertising API 5.0:Amazonの製品データ取得用のAPI
- Vercel:ホスティング
※Product Advertising APIを利用するにはAmazonアソシエイトプログラムの登録が必要です。当記事ではこちらの登録方法や使い方の説明は割愛します。
何はともあれcreate next-app
さっそくNext.jsのアプリを作成します。今回はTypeScriptとChakra UIを使いたいのでそれら既に組み込まれているテンプレートを利用します。アプリ名は何でもいいので適当に「remote-sale」にしました。
$ yarn create next-app --example with-chakra-ui-typescript remote-sale
作成後に$ yarn dev
でアプリを起動すると、 http://localhost:3000 でアクセスできるようになります。
右上のスイッチボタンでダークモードに切り替えられるのがクールですね。折角なのでどのように実装されているかソースコードを軽く追ってみましょう。
上の index.tsx がトップページのソースコードになります。Container
に囲まれているタグらが画面で表示されています。これらは純粋なHTMLタグではなく、components配下の分割されたコンポーネントファイルを読み込んで利用しているのがわかると思います。
イマドキのフロントエンドは汎用的なコンポーネントを別ファイルで定義して、それをで読み込んで使い回すのが定石のようです。
次にコンポーネントのひとつ、Container
の中身を見てみましょう。
引数を取得してFlex(これもコンポーネント)を返すシンプルなソースコードになっていますね。Flex
はChakra UIで用意されたコンポーネントです。又、同じくChakra UIで用意されているColorMode機能を利用して動的な色の変更に対応しています。useColorMode
で取得した状態に合わせてbgColor
やcolor
の値を変更することでダークモードに対応できています。
各コンポーネントで色定義をすることで影響範囲を最小限に抑えられるため、運用時に想定外の変更が起きづらいようになっていますね。「style.cssを弄ったら表示が崩れました」なんてこととはおさらばです。
そして、今回はChakra UIが見た目の実装を殆ど吸収してくれるのでCSSで消耗せずサクサク実装できます。
個人プロジェクトで特にUIにこだわらない場合であれば、こういったUIフレームワークを活用するとかなりの時短に繋がります。他にも多くのUIフレームワークがあるので用途と好みにあったものを選ぶと実装効率が上がるかもしれません。
- Material-UI: A popular React UI framework
- Base Web - Base Web React UI Framework
- Ant Design - The world's second most popular React UI framework
- Tailwind CSS - Rapidly build modern websites without ever leaving your HTML.
Product Advertising API でデータ取得
さて、やっと当記事の本題であるデータ準備にとりかかります。
※この後はNext.jsと関係ない話になるので次の記事まで読み飛ばして頂いて構いません。
Product Advertising APIの取り扱いについてはNext.jsとは関係ない部分なので、有志で公開されているnpmパッケージを利用して実装を省きます。
これでアクセスキーを用意するだけで簡単に製品データを取得できるようになりましたが、そのデータをどのように保持するかは考えなければいけません。
今回はDBやAPIサーバを用意しないため、定期的にAPIを叩いてレスポンスをJSONファイルに出力し、Next.jsではそれを参照するようにしたいと思います。
このデータの流れはこちらのソースを参考にさせて頂きました🙏
VercelやNetlifyにデプロイすることを推奨します。npm run build(or yarn build)を実行することで、RSSからの投稿データの取得とサイトのビルドが行われます。1日に1回などの頻度で自動デプロイするのが良いかもしれません。
つまり、タスクとしては大きく3つ。
- APIからデータを取得してJSONを出力するスクリプトを用意
yarn build
で上記スクリプトとサイトのビルドが行われるように設定- 定期デプロイを設定(=
yarn build
を定期実行)
今回のサイトのように動的コンテンツでない場合はこれで充分ですね。
ではさっそく実装していきます。
まずは必要なパッケージを追加
先程の「amazon-paapi」とTypeScriptのコードを直接実行できる「ts-node」、そしてファイルを簡単に取り扱えるようにする「fs-extra」を追加します。
$ yarn add amazon-paapi ts-node fs-extra
とりあえず出力のみのスクリプトを用意して直接実行できるか試してみます。
ts-node
の設定と動作確認
tsconfig.builder.jsonを作成します。
ここらへんの実装方法は先程の team-blog-hub を参考にさせていただいてます。
{ "extends": "./tsconfig.json", "compilerOptions": { "module": "commonjs", "outDir": "dist", "noEmit": false }, "exclude": ["node_modules"], "include": ["src/builder/*.ts"] }
$ ts-node --project tsconfig.builder.json ./src/builder/items.ts GET Sale Items!!
無事に出力されたので、次にデータ取得まわりを実装していきます。
残念ながら「amazon-paapi」は型定義が提供されていないので、あまり行儀がよくないですがnoImplicitAny
オプションをfalseにします。
noImplicitAny
は、型定義がない変数(any型)を禁止にするオプションです。
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "dist",
"noEmit": false,
+ "noImplicitAny": false
},
"exclude": ["node_modules"],
"include": ["src/builder/*.ts"]
}
環境変数を用意
重要なAPIキーは直書きせずに.env
で管理します。ts-nodeで参照するためにdotenvを使います。
$ yarn add dotenv
つぎに「amazon-paapi」のドキュメント通りに実装(コピペ)します。
これを叩くとこんな感じ。
$ ts-node --project tsconfig.builder.json ./src/builder/items.ts GET Sale Items!! exports { SearchResult: exports { TotalResultCount: 1200, SearchURL: 'https://www.amazon.co.jp/s?i=stripbooks&rh=p_n_availability%3A-1&tag=XXXXXXX&linkCode=osi', Items: [ [exports], [exports], [exports], [exports], [exports] ] } }
無事にレスポンスを得られました。
注意:後から気づきましたがドキュメント通りにrequestParametersにResource
を設定しても期待したリソースが返ってきません。正しくはResources
と複数形にする必要があります。
さて、次はレスポンスを整形して扱いやすいJSONにして保存します。この部分の実装についても本題ではないため、雰囲気を知っていただく程度のスクショのみで説明は割愛します。(amazon-paapiまわりは型で制御できてないですが大目に見てください)
これでデータソースとなるJSONは用意できました。定期的にts-node
を実行すればデータも更新されます。
では次の記事では満を持してNext.jsを使い、サイトを作っていきたいと思います。
※スクショ中の文字列の型を"String"と定義していますが、小文字の"string"が正しいようでした。現在は修正済みです。