Next.js で Airtable を簡易データベースとして使ってみるよ

2021.04.20

どうも、ベルリンオフィスの小西です。

ここ最近Next.jsを触っているのですが、外部DBからデータを引っ張ってくるために Airtable を利用するケースを紹介したいと思います。

Airtableとは

Excel/Googleスプレッドシートライクにデータベースを構築できるクラウドベースのアプリケーションです。

操作感はスプレッドシートに似ていて直感的でかつ、プライマリーフィールドの設定、各カラムへのデータ型の指定、デフォルト値のセットなど、RDBMS的な機能も利用できます。

APIでデータの操作もできるので、モックの簡易DBとしてサクッと使えるのも便利です。APIドキュメントも、最近よく見るタイプの、ログインしたら自分の情報がインサートされている形で素敵です。

Airtableの準備

※前段階としてAirtableに登録し、プロジェクトを作成します。

sample というテーブルを作り、

  • slug
  • Title
  • Description

というカラムを作成します。

ちなみに、レコード(一行)ごとのユニークIDと作成日はAirtable側で作成/保存されています(自分で作ってもいいけど)。

レコード取得APIの返り値は下記のようになります。 id はAirtable側で振っているユニークIDです。

{
    "id": "recbqWeotvpmDZC5P",
    "fields": {
        "Title": "テスト記事1 タイトル",
        "Description": "テスト記事1 本文本文本文本文本文本文本文本文本文本文本文",
        "slug": "test-post-1"
    },
    "createdTime": "2021-04-19T15:23:35.000Z"
}

ちなみにslugをプライマリーキーに設定してますが、Airtable側にユニークチェック機能はないので、レコードを登録する際はアプリ側もしくは運用側でユニークチェックが必要になるのでお気をつけください。

Next.jsの準備

まずさくっとNext.jsアプリを立ち上げます。

※Node.js の v10.13以降をダウンロードしておいてください。

npm init next-app sample-airtable
cd sample-airtable
npm run dev

これで http://localhost:3000/ にアクセスしてNext.jsのスタートページが立ち上がっていたらOK。いったんアプリを終了します。

パッケージのインストール

npm install airtable

環境変数ファイルの設置

.env.local

AIRTABLE_API_KEY=keyXXXXXXXX
AIRTABLE_BASE_ID=appXXXXXXXX
AIRTABLE_TABLE_NAME=sample
  • APIキーは https://airtable.com/account から [Generate API Key] で生成できます。
  • Base ID は各プロジェクトごとに発行されるので、 https://airtable.com/api からプロジェクトを選択し、次のページで [The ID of this base is appXXXXXXXX] という記載で確認できます。

Airtableクライアントを作成し、テーブルのデータを扱えるようにします。

pages/api/airtable.js

const Airtable = require('airtable');

const base = new Airtable({ apiKey: process.env.AIRTABLE_API_KEY }).base(
  process.env.AIRTABLE_BASE_ID
);

const table = base(process.env.AIRTABLE_TABLE_NAME);

export { table };

次に、pagesディレクトリの配下に posts.js を作成し、下記の記述をします。

src/pages/posts.js

import Head from 'next/head'
import styles from '../styles/Home.module.css'
import { table } from './api/airtable';

export default function Posts({ airtableRecords }) {
  return (
    <div className={styles.container}>
      <Head>
        <title>posts from Airtable</title>
      </Head>
      <main className={styles.main}>
        <h1 className={styles.title}>
          Posts
        </h1>
        <div>
          {
            airtableRecords.map((record) => 
              <div style={{margin: 10, padding: 10, border: "solid 1px gray"}} key={record.id}>
                <h2>{record.fields.Title}</h2>
                <p>{record.fields.Description}</p>
              </div>
            )
          }
        </div>
      </main>
    </div>
  )
}

export async function getStaticProps(context) {
  let airtableRecords = await table
    .select({
      maxRecords: 10,
      sort: [
        {field: 'slug', direction: 'asc'},
        {field: 'Title', direction: 'desc'},
      ],
    })
    .firstPage();
  airtableRecords = airtableRecords.map((record) => {
    return {
      id: record.id,
      fields: record.fields
    }
  });
  return {
    props: {
      airtableRecords: airtableRecords,
    },
  };
}

ざっくり posts.js 内容の説明

静的ページとしてビルドするため getStaticProps の中で処理をしています。

select はレコードの諸々のデータが入ったオブジェクトを返すメソッドですが、中でオプションを指定できます。上記の例ではMAXのレコード数とソートを指定していますが、下記の例のようにフィールドの値で絞り込みなども行えます。

.select({
	//slugがtest-post-3のレコードを除外する
	filterByFormula: "NOT({slug} = 'test-post-3')"
})

また firstPage メソッドは返り値のページ数の指定です。Airtableはデフォルトで最大100件までのレコードを1ページとして返すのですが、今回はそれ以下の数なので firstPage を指定しています。100を超える場合は eachPage メソッドを使いましょう。

詳しくは https://airtable.com/api に載っています。

データが取得できたかの確認

以上の準備を終えた上で、再度 npm run dev をして http://localhost:3000/posts にアクセスすると、下記のように記事が生成されているのが確認できると思います。

以上、非常に簡単に外部データをNext.js上で表示できました。

今回はビルド時にAirtableのデータを引っ張ってきてループで書き出す処理をしただけですが、Auth0と組み合わせて簡単なユーザーデータベースなども作成できます。

また今回は使っていないslugカラムをベースに記事詳細ページも生成したりできますね。

セットアップ不要でエンドポイントのある簡易データベースを使えるという意味でAirtableはこれから重宝しそうです。

参考記事

https://github.com/Airtable/airtable.js