みかづきブログ・カスタム

基本的にはちょちょいのほいです。

@shopify/shopify-api(shopify-node-api)を使わずにShopifyのブログ記事一覧をNext.jsでつくったAPIで強引に取得する 📝

f:id:kimizuka:20220116224431j:plain

なにか根本的なところを間違えている気がしてならないのですが、強引な手法でShopifyのブログ記事一覧を取得できたのでメモを残しておきます。

結論

src/pages/api/getArticles.js

import axios from 'axios';

export default async function getArticleList(req, res) {
  const { data } = await axios.get(`https://your-development-store.myshopify.com/admin/api/2021-10/blogs/${ process.env.SHOPIFY_BLOG_ID }/articles.json`, {
    auth: {
      username: process.env.SHOPIFY_APP_USERNAME,
      password: process.env.SHOPIFY_APP_PASSWORD
    }
  });

  res.status(200).json(data);
}

という形のAPIを作ることでブログ記事一覧を取得できました。

ことの発端

ECサイト用CMSとして名高いShopify

www.shopify.jp

APIも提供されていて、Next.jsとの相性も悪く無いので、ECサイトを作るときは、Next.js + Shopifyで構築しています。
shopifyのAPIを簡単に扱えるように、npmモジュールも公開されていて、僕は、shopify-buyjs-buy-sdk)を使っていて、大体の機能はこれで事足りるのですが、先日これだけではカバーできない部分が出てきました。それがブログ機能です。

Shopifyにはブログ機能が備わっているのですが、ブログ記事をAPIから取得しようとすると、js-buy-sdkでは不充分だったので、もろもろ調査をはじめました。

すると、すぐに情報は見つかりました。

shopify.dev
shopify.dev

Admin APIのblogs.jsonを叩いてblog_idを取得し、そのblog_idを元に、articles.jsonを叩けば記事が取得できるようです。

@shopify/shopify-apishopify-node-api)というnpmモジュールも公開されてますし、きっと楽勝だ。と思いながら、まずは、blog_idを取得を試みました。

(async () => {
  const { Shopify } = require('@shopify/shopify-api');

  const client = new Shopify.Clients.Rest('your-development-store.myshopify.com', accessToken);
  const data = await client.get({
    path: 'blogs',
  });

  console.log(data);
})();

と、ほぼほぼサンプルコードのままなのですが、accessTokenの取得方法を調べると、

こちらのサンプルのように書く必要があることがわかりました。

const session = await Shopify.Utils.loadCurrentSession(req, res);
const client = new Shopify.Clients.Rest(session.shop, session.accessToken);
const response = client.get({path: 'shop'});


若干面倒です。
どうにかセッションを使わずにJSONの取得ができないかなと思い、curlでの例に記載されたURL、

curl -X GET "https://your-development-store.myshopify.com/admin/api/2022-01/blogs.json" \
-H "X-Shopify-Access-Token: {access_token}"

https://your-development-store.myshopify.com/admin/api/2022-01/blogs.json にブラウザのシークレットモードでアクセスしてみると、Basic認証が掛かっており、

AdminAPIの、

APIキー 👉 ユーザ名
パスワード 👉 パスワード

の入力を求められたのち、JSON形式でブログの一覧が表示されました。
ここに表示されたblog_idをメモし、このIDを使ってブログ記事一覧を取得しようと思います。

実装方針

シークレットブラウザでの挙動から察するに、Basic認証を突破できる情報を持ったGETリクエストを投げることができれば、@shopify/shopify-apishopify-node-api)を使わずともブログ記事の一覧が取得できそうです。

Next.jsは簡単にAPIを作成することができるので、axiosを使ってBasic認証を突破するAPIを作ってJSONを取得することにしました。それが冒頭のコードです。
リクエストを投げるのはfetchでもよかったのですが、使い慣れているaxiosにしました。

src/pages/api/getArticles.js

import axios from 'axios';

export default async function getArticleList(req, res) {
  const { data } = await axios.get(`https://your-development-store.myshopify.com/admin/api/2021-10/blogs/${ process.env.SHOPIFY_BLOG_ID }/articles.json`, {
    auth: {
      username: process.env.SHOPIFY_APP_USERNAME,
      password: process.env.SHOPIFY_APP_PASSWORD
    }
  });

  res.status(200).json(data);
}

authにユーザー名、パスワードのオブジェクトをつければBasic認証を突破できます。

繰り返しになりますが、ユーザー名は、Admin APIのAPIキー、パスワードはAdmin APIのパスワードなので、

  1. 事前にプライベートアプリをつくる
  2. Admin APIにストアコンテンツの読み取りアクセスの権限を与える
  3. APIキー、パスワードを控える

が必要になります。
公式のヘルプセンターの手順に従えば問題ありません。

help.shopify.com


取得したAPIキー、パスワードに加え、ブラウザのアクセスで取得したブログIDはまとめてenvに記載しています。

懸念としては、ブログ記事が251件以上あった場合で、[https://shopify.dev/api/admin-rest/2022-01/resources/article#[get]/admin/api/2022-01/blogs/{blog_id}/articles.json:title=Article]のlimitの上限が250にも関わらず、ページャーのようなものが見当たらないので、250件目以降の記事を取得する方法がわかりません。

同様にブログの取得も250件までいけるので、1つのブログに記事を250件投稿するたびに、新しいブログを作れば、62,500件までは記事を所得できるので問題なさそうですが、GraphQL Admin APIArticleを確認するとページングできそうなので、素直にGraphQL Admin APIを使った方が良いのかもしれないです。

参考にしたサイト

community.shopify.com