Shopifyアプリ(Remix)の開発 – Graphql API利用、注文情報リストの表示

Shopify

はじめに

開発

アプリ作成

% shopify app init

Welcome. Let’s get started by naming your app project. You can change it later.

?  Your project name?
✔  s3lab-app-2

?  Get started building your app:
✔  Start with Remix (recommended)

?  For your Remix template, which language do you want?
✔  TypeScript

╭─ info ───────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                              │
│  Initializing project with `npm`                                                             │
│  Use the `--package-manager` flag to select a different package manager.                     │
│                                                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯


╭─ success ────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                              │
│  s3lab-app-2 is ready for you to build!                                                      │
│                                                                                              │
│  Next steps                                                                                  │
│    • Run `cd s3lab-app-2`                                                                    │
│    • For extensions, run `shopify app generate extension`                                    │
│    • To see your app, run `shopify app dev`                                                  │
│                                                                                              │
│  Reference                                                                                   │
│    • Shopify docs [1]                                                                        │
│    • For an overview of commands, run `shopify app --help`                                   │
│                                                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
[1] https://shopify.dev
% npm run dev

> dev
> shopify app dev


Before proceeding, your project needs to be associated with an app.

?  Create this project as a new app on Shopify?

>  (y) Yes, create it as a new app
   (n) No, connect it to an existing app

   Press ↑↓ arrows to select, enter or a shortcut to confirm.

(arm64) masayukimatsuo@s3l-mbp-202110-2 s3lab-app-2 % shopify app dev

Before proceeding, your project needs to be associated with an app.

?  Create this project as a new app on Shopify?
✔  Yes, create it as a new app

?  App name:
✔  s3lab-app-2

?  Which store would you like to use to view your project?
✔  s3labteststore2

shopify.app.tomlにスコープを追加

[access_scopes]
scopes = "read_customers,read_orders,read_products,write_orders,write_products"

スコープをPartner管理画面のアプリに同期するためにデプロイ実行

shopify app deploy

注意: –resetをつけた場合、逆にPartner管理画面のスコープでshopify.app.tomlのスコープが上書きされる

Partner管理画面にスコープが同期されたことを確認

カスタムアプリとしてDistribute実行

  • distributeしないとアプリ注文の表示ができず、以下のエラーが表示された
    • Error: This app is not approved to access the Order object shopify

Shopifyアプリでの注文情報表示を確認

ソースコード

app/routes/app.orders.jsx

import {
    IndexTable,
    Page, 
} from "@shopify/polaris";
import { authenticate } from "../shopify.server";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";

export const meta = () => {
    return [{ title: "Orders" }];
};

export const loader = async ({ request }) => {
    const { admin } = await authenticate.admin(request);
    const response = await admin.graphql(
        `query MyQuery {
        orders(first: 50, reverse: true,) {
          edges {
            node {
              id
              createdAt
              customer {
                firstName
              }
              displayFulfillmentStatus
              email
              originalTotalPriceSet {
                presentmentMoney {
                  amount
                  currencyCode
                }
              }
            }
          }
        }
      }`);
    const responseJson = await response.json();
    const orders = await responseJson?.data?.orders?.edges?.map(row => row?.node).map(
        row => {
            return {
                ...row,
                ...row?.customer,
                ...row?.originalTotalPriceSet?.presentmentMoney
            }
        }
    );
    return json({
        orders
    });
};

export default function Orders() {
    const { orders } = useLoaderData();
    const resourceName = {
        singular: 'order',
        plural: 'orders',
    };
    const rowMarkup = orders.map(
        (
            { id, amount, createdAt, email, firstName },
            index,
        ) => (
            <IndexTable.Row
                id={id}
                key={id}
                position={index}
            >
                <IndexTable.Cell>#{id?.replace('gid://shopify/Order/', '')}</IndexTable.Cell>
                <IndexTable.Cell>{firstName}</IndexTable.Cell>
                <IndexTable.Cell>{email}</IndexTable.Cell>
                <IndexTable.Cell>{amount}</IndexTable.Cell>
                <IndexTable.Cell>{createdAt}</IndexTable.Cell>
            </IndexTable.Row>
        ),
    );
    return (
        <Page title="Orders" fullWidth>
            <IndexTable
                resourceName={resourceName}
                itemCount={orders.length}
                headings={[
                    { title: 'Order Id' },
                    { title: 'Name' },
                    { title: 'Email' },
                    { title: 'Total' },
                    { title: 'Created' },
                ]}
                selectable={false}
            >
                {rowMarkup}
            </IndexTable>
        </Page>
    );
}

app/data.ts

import { matchSorter } from "match-sorter";
import sortBy from "sort-by";
import invariant from "tiny-invariant";

type MeetingMutation = {
    id?: string;
  };
  
export type MeetingRecord = MeetingMutation & {
  id: string;
  createdAt: string;
};
  
const Meetings = {
  records: {} as Record<string, MeetingRecord>,

  async getAll(): Promise<MeetingRecord[]> {
    return Object.keys(Meetings.records)
      .map((key) => Meetings.records[key])
      .sort(sortBy("-createdAt", "last"));
  },

  async get(id: string): Promise<MeetingRecord | null> {
    return Meetings.records[id] || null;
  },

  async create(values: MeetingMutation): Promise<MeetingRecord> {
    const id = values.id || Math.random().toString(36).substring(2, 9);
    const createdAt = new Date().toISOString();
    const newMeeting = { id, createdAt, ...values };
    Meetings.records[id] = newMeeting;
    return newMeeting;
  },

  async set(id: string, values: MeetingMutation): Promise<MeetingRecord> {
    const meeting = await Meetings.get(id);
    invariant(meeting, `No meeting found for ${id}`);
    const updatedMeeting = { ...meeting, ...values };
    Meetings.records[id] = updatedMeeting;
    return updatedMeeting;
  },

  destroy(id: string): null {
    delete Meetings.records[id];
    return null;
  },
};

export async function getMeetings(query?: string | null) {
  let meetings = await Meetings.getAll();
  if (query) {
    meetings = matchSorter(meetings, query, {
      keys: ["first", "last"],
    });
  }
  return meetings.sort(sortBy("last", "createdAt"));
  }

shopify.app.toml

・・・

[access_scopes]
scopes = "read_customers,read_orders,read_products,write_orders,write_products"

・・・

.env

SHOPIFY_API_KEY=
SHOPIFY_API_SECRET=

関連記事

カテゴリー

アーカイブ

Lang »