GatsbyでAirtableからデータを読む
Gatsbyのプロジェクトで、Airtableからデータを読む方法のメモです。
親切なAirtableのヘルプ
- Airtableでワークスペースを開き、そこから次のように[API doucumentation]を選択すると、このワークスペースでレコード(テーブルの行)をリストしたり、レコードを作成、更新、削除するための具体的なコードまで示されていて大変親切です。
例えば、次のようなコードを書きます。
const IndexPage = () => {
const Airtable = require('airtable');
const base = new Airtable({ apiKey: `${process.env.AIRTABLE_API_KEY}` }).base(
`${process.env.AIRTABLE_BASE_ID}`
);
base('Members directory')
.select({
maxRecords: 100,
view: 'Key members',
})
.eachPage(
(records, fetchNextPage) => {
records.forEach((record) => {
console.log('Name: ', record.get('Name'), ' Title: ', record.get('Title'), record.get('Photo'));
});
fetchNextPage();
},
(err) => {
if (err) {
console.error(err);
return;
}
}
);
なお、環境変数を使用できるようにするには、gatsby-config.js に次を追加します。
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`,
});
すると、コンソールには次のような結果が得られました。
- しかし、Gatsby では、ローカルのファイル(マークダウン等)や様々なデータ源について、GraphQL のクエリですべて持ってこれるので、Airtable からのデータ取得もそのクエリで取得できるとスマートかと思います。
gatsby-source-airtable のインストール
gatsby-source-airtable は Airtable のテーブルより Gatsby アプリケーションにデータを取り込むためのプラグインです。次でインストールします。
$ npm install gatsby-source-airtable $ npm audit fix // 必要な場合
gatsby-config.js の plugins の設定の一部を次のようにします。
plugins: [
{
resolve: `gatsby-source-airtable`,
options: {
apiKey: `${process.env.AIRTABLE_API_KEY}`,
concurrency: 5,
tables: [ // 複数指定可
{
baseId: `${process.env.AIRTABLE_BASE_ID}`,
tableName: `Members directory`,
// tableView: `YOUR_TABLE_VIEW_NAME`, // optional
// queryName: `OPTIONAL_NAME_TO_IDENTIFY_TABLE`, // optional
// mapping: { `CASE_SENSITIVE_COLUMN_NAME`: `VALUE_FORMAT` }, // optional
// tableLinks: [`CASE`, `SENSITIVE`, `COLUMN`, `NAMES`], // optional
separateNodeType: false,
separateMapType: false,
},
]
}
},
:
この状態で gatsby develop して開発サーバーが起動した状態で、http://localhost:8000/___graphql にアクセスし、GraphiQL のクエリを次のようにしてみます。
query MyQuery {
allAirtable(sort: {fields: data___Order, order: ASC}) {
nodes {
data {
Name
Title
Photo {
id
url
}
}
}
}
}
ここで sort を指定しているのは、Airtable のレコードの並び順に出力するためです。もっと良い方法があるかもしれませんが、ここでは Airtable に Order を設定し、その値の昇順にソートするようにしました。
これにより GraphQL でクエリを実行すると次になります。
この方法では画像のURLが得られましたが、これを親コンポーネントの props で受け取り、gatsby-plugin-image の StaticImage を用いることはできません(詳細はこちら)。画像を Airtableなど CMS から読み込み場合は、GraphQL を介して画像を読み込み、GatsbyImage コンポーネントを使用する必要があります。
AirtableのAttachmentフィールドをGraphQLで読めるようにする方法
この方法は、gatsby-source-airtable のこちらに記載しています。
まず、gatsby-config.js に次のように mapping の設定をします。この例では、Photo とあるのが、Airtable の Attachment フィールドタイプの field 名になります。
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`,
});
module.exports = {
plugins: [
{
resolve: `gatsby-source-airtable`,
options: {
apiKey: process.env.AIRTABLE_API_KEY,
concurrency: 5,
tables: [ // 複数指定可
{
baseId: process.env.AIRTABLE_BASE_ID,
tableName: process.env.AIRTABLE_TABLE_NAME,
mapping: { Photo: `fileNode` }, // optional
separateNodeType: false,
separateMapType: false,
},
]
}
},
この設定にしておくと次のように gatsbyImageData をクエリできるようになります。
const TeamMembers = () => {
const data = useStaticQuery(graphql`
query {
allAirtable(sort: { order: ASC, fields: data___Order }) {
nodes {
data {
Name
Bio
Homepage_URL
Twitter_username
GitHub_username
Instagram_username
YouTube_username
Photo {
localFiles {
childImageSharp {
gatsbyImageData(
width: 200
layout: FIXED
placeholder: BLURRED
formats: [AUTO, WEBP, AVIF]
)
}
}
}
}
}
}
}
`);
データのコンポーネントへの設定
今回は既にあるプロジェクトの都合で次のようにデータを teamMembers という配列に入れているのですが、Airtable の Attachmentフィールドタイプの Photo には複数の写真が入るので、先頭の写真だけを格納しています。
import React from 'react';
import { useStaticQuery, graphql } from 'gatsby';
import styled from 'styled-components';
import TeamMember from './TeamMember';
const TeamMembersWrapper = styled.div`
color: purple;
`;
const TeamMembers = () => {
const data = useStaticQuery(graphql`
query {
allAirtable(sort: { order: ASC, fields: data___Order }) {
nodes {
// 省略。上と同じです。
}
}
`);
// GraphQLで取得したAirtableのデータを元のスターターの形式のオブジェクト配列に設定
const teamMembers = [];
data.allAirtable.nodes.forEach((node) => {
teamMembers.push({
file: node.data.Photo.localFiles[0],
header: node.data.Name,
subheader: node.data.Bio,
social: {
homepage: node.data.Homepage_URL,
twitter: node.data.Twitter_username,
github: node.data.GitHub_username,
instagram: node.data.Instagram_username,
youtube: node.data.YouTube_username,
},
})
});
return (
<TeamMembersWrapper>
{teamMembers.map((member) => (
<TeamMember member={member} key={member.header} />
))}
</TeamMembersWrapper>
);
};
export default TeamMembers;
データの表示
この実験用コードでは次のように表示します。
コードは次のようになっています。
import React from 'react';
import styled from 'styled-components';
import { GatsbyImage, getImage } from 'gatsby-plugin-image';
const TeamMemberWrapper = styled.div`
margin: 2em;
padding: 1em;
border: 1px solid black;
`;
const TeamMember = ({ member }) => {
return (
<TeamMemberWrapper>
<GatsbyImage image={getImage(member.file)} alt={member.header} />
<h1>{member.header}</h1>
<p>{member.subheader}</p>
{member.social.homepage && <p>ホームページ: {member.social.homepage}</p>}
{member.social.twitter && <p>Twitter: {member.social.twitter}</p>}
{member.social.github && <p>GitHub: {member.social.github}</p>}
{member.social.instagram && <p>Instagram: {member.social.instagram}</p>}
{member.social.youtube && <p>YouTube: {member.social.youtube}</p>}
</TeamMemberWrapper>
);
};
export default TeamMember;
ここでは、ヘルパー関数の getImage を使って、次のように短く書くようにしています。
<GatsbyImage image={member.file.childImageSharp.gatsbyImageData} alt={member.header} />
↓
<GatsbyImage image={getImage(member.file)} alt={member.header} />
ソースコード全体はこちらになります。
ディスカッション
コメント一覧
まだ、コメントがありません