Newt は昨年にローンチされた国産のヘッドレスCMSで、元プレイドの方々が「次のWordPressをつくる」をミッションとして開発されているサービスです。
競合として同じく国産の microCMS は以前に触ったことがあったため、今回は比較も兼ねてNewtを使用してみることにしました。
ざっくり次のような流れになります。
まずはCMS側でコンテンツ(データ)を登録しておきます。
サインアップ画面 からアカウントを登録後、スペースを作成します。
スペースはひとつのプロジェクト単位にあたります。
Appを追加します。 Appは簡単に言うとモデルとビューを含んだモジュールで、ひとつのスペースにAppをいくつか登録する構成になります。
例えば「お知らせ」Appと「制作実績」Appでそれぞれ分けて作成するようなイメージで、WordPressのカスタム投稿タイプに粒度基準の考え方は近そうです。
Appには、
の3種類があります。
モデル、ビュー、ダミーコンテンツが予めセットされたAppテンプレートを管理画面から1クリックでインストールできます。GitHubに公開されているスターターと組み合わせて使う事ができます。
例えばブログの一覧/詳細/検索結果セットのテンプレートがあり、細かい要件がなく素早く作りたいなどの際に使えそうです。
タイプは、モデルとビューを自身で作成する際に使用します。
今回はこのタイプの「CMS App」を使用します。
Newt上で管理しているモデル、ビュー、コンテンツ、メディア等のデータを、App単位でエクスポート(JSON形式)することができます。
ファイルは使い所がしっくりきていませんが、無料プランでは使用できません。
CMS Appを追加します。
左のナビゲーションに「test-app」が追加されたので、モデルを作成します。
今回はサンプルのため適当なモデル名で作成します。
モデルができたら、フィールドを作成します。
画面右側にフィールドの種類がでているので、設定をしていきます。
追加すると一覧に表示されます。
JSONプレビューに切り替えると、JSONのサンプルが確認できます。
取り急ぎフィールドはここまでで、次にコンテンツを登録します。
スペースのトップに戻って、「test-modelを追加」を押します。
コンテンツ登録をします。
「保存して公開」を押すと一覧に表示されます。
テストで3件公開してみました。
コンテンツ登録については以上です。
主に クイックスタート の通りに進めていきます。
エンドポイントは下記のフォーマットになるので、
https://{spaceUid}.cdn.newt.so/v1/{appUid}/{modelUid}
今回の場合、下記に置き換えます。
https://next-sample.cdn.newt.so/v1/test-app/test-model
APIキーの発行を「スペース設定」>「APIキー」より行います。
Newt CDN API から「作成」します。
取得対象のカスタマイズ(○○Appのみ、など)も可能です。
curl -H "Authorization: Bearer {YOUR_TOKEN}" \ -X GET "https://next-sample.cdn.newt.so/v1/test-app/test-model"
フォーマットに合わせてcurlでリクエストすると登録したコンテンツのレスポンスが返ってきました。
API取得については以上です。
Next.jsを利用して登録コンテンツの表示を行います。
前回までに create-next-app コマンドでプロジェクトを作成していたので、そのリポジトリを使用します。
主に チュートリアル 通りに進めていきます。
.env.local
ファイルを作成しスペースUIDとトークンの定義をします。
NEWT_SPACE_UID=next-sample NEWT_CDN_API_TOKEN=xxxxxxxxxxxxxxx
Newt用のJavaScriptクライアントSDKをインストールします。
npm install newt-client-js
インストールしたSDKを使ってクライアントを作成します。
// lib/newt.js import { createClient } from 'newt-client-js' const client = createClient({ spaceUid: process.env.NEWT_SPACE_UID + '', token: process.env.NEWT_CDN_API_TOKEN + '', apiType: 'cdn', })
投稿一覧の取得メソッドを作成し、一覧を表示します。
// lib/newt.js export const getArticles = async () => { const { items } = await client.getContents({ appUid: 'test-app', modelUid: 'test-model', query: { select: ['_id', 'title', 'slug', 'body'], }, }) return items }
// pages/index.js import Head from 'next/head' import Link from 'next/link' import { getArticles } from '../lib/newt' export default function Home({ articles }) { return ( <> <Head> <title>Newt・Next.jsブログ</title> <meta name="description" content="NewtとNext.jsを利用したブログです" /> </Head> <main> <ul> {articles.map((article) => { return ( <li key={article._id}> <Link href={`test-model/${article.slug}`}>{article.title}</Link> </li> ) })} </ul> </main> </> ) } export const getStaticProps = async () => { const articles = await getArticles() return { props: { articles, }, } }
投稿詳細の取得メソッドを作成し、一覧を表示します。
// lib/newt.js export const getArticleBySlug = async (slug) => { const article = await client.getFirstContent({ appUid: 'test-app', modelUid: 'test-model', query: { slug, select: ['_id', 'title', 'slug', 'body'], }, }) return article }
// test-model/[slug].js import Head from 'next/head' import { getArticles, getArticleBySlug } from '../../lib/newt' export default function Article({ article }) { return ( <> <Head> <title>{article.title}</title> <meta name="description" content="投稿詳細ページです" /> </Head> <main> <h1>{article.title}</h1> <div dangerouslySetInnerHTML={{ __html: article.body }} /> </main> </> ) } export const getStaticPaths = async () => { const articles = await getArticles() return { paths: articles.map((article) => ({ params: { slug: article.slug, }, })), fallback: false, } } export const getStaticProps = async ({ params, }) => { const { slug } = params const article = await getArticleBySlug(slug) return { props: { article, }, } }
Next.jsのコードをVercelへデプロイします。
プロジェクトトップ > 「Settings」 > 「Environment Variables」から NEWT_SPACE_UID
と NEWT_CDN_API_TOKEN
を設定します。
ブランチへプッシュ、デプロイして無事にサクセスになりました。
https://next-sample-yuheijotaki.vercel.app/
/**/[slug].js
など、ディレクトリで分ける方法はVueのNuxt.jsと変わりなく、これくらいのレベルだと違和感なく作れた。