LCL Engineers' Blog

バス比較なび・格安移動・バスとりっぷを運営する LCLの開発者ブログ

バックエンドが要らない手軽なサイトをNext.jsで作ってみた【データ準備編】

この記事はLCL Advent Calendar 2020 - 6日目です。

qiita.com

ユーザに見えるところの開発が好きなモバイルアプリエンジニアの山下です。

業務ではモバイルアプリ以外にバックエンドやインフラを広く浅く担当していますが、チームの技術スキルが上がると共にキャッチアップする量が増えていき限界を感じつつあります(汗)最近は後者の比率も多く、その反動で個人的にwebサービスを作りたい思いが芽生えてきたので自粛期間中に流行のNext.jsを少し触っていました。

モバイルアプリのようにビルドを待つこともなければ、TypeScriptを使えばRailsのように型で消耗することもないので開発効率が良いですし、Vercelを使えば簡単に無料でホスティングしてくれるので最高の開発体験に感動しています。

とはいえ、生きたサイトを作るとなるとバックエンド(APIやDB)を用意する必要がありますよね。ラクをしようとAWS Amplifyを試してみたもののDynamoDBの扱いに苦戦して(というかこれで消耗したくなくて)挫折しました...。

AWS AmplifyはRDS(Aurora)やSSRに対応してない訳ではないですが、調べると痒いところだらけな雰囲気を感じるのでいい感じに統合されることを期待してもう暫く様子見し、その間にバックエンドが要らない手軽なサイトを作ろうと思い、こんなものを作ってみました。

Remote 🏠 Sale|Amazonレビュー★4以上のリモートワークが捗る製品情報をお届け

remote-sale.vercel.app

f:id:yamshta:20201207150317p:plain

イチペラのAmazonリンクが並べてあるだけのサイトです。もう少しちゃんとしたものを作るつもりが、チュートリアルにも満たないサイトになってしまいました(汗)

まあ折角なのでどのように実装したかを簡単に紹介していきます。Next.jsの中身については薄くなってしまいますが、アプリ作成からデプロイまでの雰囲気は掴んで頂けるかと思います。

私のような初学者でも分かりやすいようにスクショ多めで「データ準備編」、「サイト公開編」、「Next.js活用編」の三部構成でお届けします。

材料

※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 でアクセスできるようになります。

f:id:yamshta:20201207150338p:plain

右上のスイッチボタンでダークモードに切り替えられるのがクールですね。折角なのでどのように実装されているかソースコードを軽く追ってみましょう。

f:id:yamshta:20201207150352p:plain

上の index.tsx がトップページのソースコードになります。Containerに囲まれているタグらが画面で表示されています。これらは純粋なHTMLタグではなく、components配下の分割されたコンポーネントファイルを読み込んで利用しているのがわかると思います。

イマドキのフロントエンドは汎用的なコンポーネントを別ファイルで定義して、それをで読み込んで使い回すのが定石のようです。

次にコンポーネントのひとつ、Containerの中身を見てみましょう。

f:id:yamshta:20201207150421p:plain

引数を取得してFlex(これもコンポーネント)を返すシンプルなソースコードになっていますね。FlexはChakra UIで用意されたコンポーネントです。又、同じくChakra UIで用意されているColorMode機能を利用して動的な色の変更に対応しています。useColorModeで取得した状態に合わせてbgColorcolorの値を変更することでダークモードに対応できています。

chakra-ui.com

各コンポーネントで色定義をすることで影響範囲を最小限に抑えられるため、運用時に想定外の変更が起きづらいようになっていますね。「style.cssを弄ったら表示が崩れました」なんてこととはおさらばです。

そして、今回はChakra UIが見た目の実装を殆ど吸収してくれるのでCSSで消耗せずサクサク実装できます。

個人プロジェクトで特にUIにこだわらない場合であれば、こういったUIフレームワークを活用するとかなりの時短に繋がります。他にも多くのUIフレームワークがあるので用途と好みにあったものを選ぶと実装効率が上がるかもしれません。

Product Advertising API でデータ取得

さて、やっと当記事の本題であるデータ準備にとりかかります。

※この後はNext.jsと関係ない話になるので次の記事まで読み飛ばして頂いて構いません。

Product Advertising APIの取り扱いについてはNext.jsとは関係ない部分なので、有志で公開されているnpmパッケージを利用して実装を省きます。

github.com

これでアクセスキーを用意するだけで簡単に製品データを取得できるようになりましたが、そのデータをどのように保持するかは考えなければいけません。

今回はDBやAPIサーバを用意しないため、定期的にAPIを叩いてレスポンスをJSONファイルに出力し、Next.jsではそれを参照するようにしたいと思います。

このデータの流れはこちらのソースを参考にさせて頂きました🙏

zenn.dev

github.com

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の設定と動作確認

f:id:yamshta:20201207150442p:plain

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」のドキュメント通りに実装(コピペ)します。

f:id:yamshta:20201207150500p:plain

これを叩くとこんな感じ。

$ 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まわりは型で制御できてないですが大目に見てください)

f:id:yamshta:20201207150517p:plain

これでデータソースとなるJSONは用意できました。定期的にts-nodeを実行すればデータも更新されます。
では次の記事では満を持してNext.jsを使い、サイトを作っていきたいと思います。

※スクショ中の文字列の型を"String"と定義していますが、小文字の"string"が正しいようでした。現在は修正済みです。

techblog.lclco.com