Amazon Web Services ブログ
ヘッドレスコマース型の小売ストアをCommercetools と統合する方法 – Part 1
独自の購買体験を生み出し、その体験を阻害する摩擦要因を減らして顧客エンゲージメントを高めるための差別化要素として、近年、多くの小売企業が最新の e コマース戦略を採用して来ました。ヘッドレスコマースは、オンラインストアのフロント技術がバックエンドのコマース機能から切り離されていることで注目を集めているアプローチの一つです。ヘッドレスコマースでは、バックエンドの小売共通ビジネスロジックをクラウドベースのマイクロサービスとして実装し、そのバックエンドマイクロサービスに対してそれぞれのストアフロントのユーザーインターフェース(UIs)、例えば小売店舗の POS システム、e コマースウェブサイト、モバイルアプリのインターフェースなどからアクセスします。
ヘッドレスコマースソリューションのもたらす利点には以下のようなものがあります:
- 一貫性のある顧客体験 – 価格設定、プロモーション、注文履歴といった小売業務に共通のバックエンド機能により、あらゆる販売チャネルで一貫性のある顧客体験を実現できます。
- カスタマイズとパーソナライズ – ヘッドレスコマースではフロントエンドとバックエンドの機能が分離されているため、さまざまなフロントエンド UI ごとにカスタマイズされたデザインとレイアウトを作成できます。
- 拡張性 – さまざまな販売チャネルに共通のバックエンド機能を使用することで、ブランドを表現し、グローバルに機能拡張できるフロントエンドの顧客体験の創出に、より多くの時間を費やすことができます。
- 実験と革新 – ヘッドレスコマースの分離されたアーキテクチャでは、開発者がフロントエンドとバックエンドのコードを同時に編集する必要がありません。開発者は新しいアイデアや機能をより迅速に試すことができます。
モダンな MACH (microservices, API-first, cloud-native, headless) アーキテクチャにおいて、ヘッドレスコマースは 1 つの原則となっています。アマゾンウェブサービス(AWS)は最近 MACH アライアンスに参加してイノベーションを促進するとともに、より優れた顧客体験を提供するべくモダンアーキテクチャを実装したいと考えている企業、小売企業、消費財(CPG)企業を支援しています。
commercetools を利用したヘッドレスコマース
AWS パートナー企業である commercetools は、MACH 原則に基づいて構築された、先進的なコマースソリューションを提供しています。このソリューションは AWS クラウド上に、高品質でスケーラブルな、最新の e コマースアーキテクチャを構築するためのツールを顧客に提供します。commercetools はすぐに利用できるソリューションであり、小売、食料品、ファッション、およびその他の業界における著名な e コマースブランドで採用され、信頼を得ています。
commercetools は、モダンな e コマースソリューションの厳しいニーズを満たすよう設計された、一連の柔軟な REST および GraphQL API を提供しています。これらの API は、ソリューションおよび関連機能に保存されているデータにプログラムベースでアクセスするためのインターフェイスを作成します。
開発者は以下の方法で commercetools ソリューションを利用できます:
- ソリューションを AWS の人工知能(AI)、機械学習(ML)サービスと統合します。たとえば、Amazon Personalize では、パーソナライズされたユーザー体験をほぼリアルタイムに、かつ大規模・高速に作成できます。Amazon Forecast ではビジネスメトリクス分析のために構築された ML ベースの 時系列予測ができます。
- Amazon EventBridge や Amazon Simple Notification Service (Amazon SNS)を使用してイベント駆動のプロセスを開始できます。Amazon EventBridge は、AWSや既存システム、あるいは Software-as-a-Service(SaaS)アプリケーションをまたいでイベント駆動型アプリケーションを大規模に構築することのできるサーバーレスなイベントバスです。Amazon SNS はアプリケーション間通信、アプリケーションとユーザー間の通信、いずれにも利用できるフルマネージドのメッセージングサービスです。
- AWS Amplify を使用して、拡張性のあるウェブ、およびモバイルインターフェイスを構築します。AWS Amplify は、開発者が拡張性のあるフルスタックのウェブアプリ、モバイルアプリを、より高速に構築できるようにするための専用のツールと機能のセットを提供するものです。
- サーバーレスのイベント駆動型コンピューティングサービスである AWS Lambda 関数を挿入することで、独自のビジネスロジックを追加できます。AWS Lambda を使えば、サーバーをプロビジョニング、管理することなく、commercetools の API 拡張機能を介してあらゆるタイプのアプリケーションやバックエンドサービスのコードを実行できます。
このブログでは、e コマースストアのフロントエンドインターフェイスとして AWS リテールデモストアを使用し、JavaScript のソフトウェア開発キット(SDK)から commercetools API を呼び出して注文管理機能を実装するプロセスを解説します。AWS リテールデモストアは学習目的のコードであり、本番環境での使用を意図していない点はご了承ください。(訳注: AWS リテールデモストアについてはブログ「魅力的な顧客体験を提供するプラットフォームを学習できるリテールデモストアの紹介」で紹介しています。)
注文マイクロサービスの実装
AWS リテールデモストアで提供している注文マイクロサービスは、注文を生成、取得するためのインターフェースです。買い物客が注文を表示したり、チェックアウトプロセスを完了したりすると、ウェブ UI はこのサービスを呼び出します。ウェブ UI が注文マイクロサービスに期待するインターフェースは以下です:
実装を開始する前に、commercetools でアカウントを作成する必要があります。サービスを試してみたいのであれば 60 日間の無料トライアルにサインアップすることもできます。「commercetools 入門」のチュートリアル手順に従って、API クライアントを設定することをお勧めします。 今回の実装プロセスでもクライアントを使用します。
まず、commercetools API を呼び出すクライアントを作成します。commercetools Merchant Center から API クライアントを作成するのであれば、使いたい SDK やツールに応じたさまざまな形式のクライアントの資格情報(クレデンシャル)をダウンロードできます。以下のコードは JavaScript SDK での例です。
const {
ClientBuilder,
createAuthForClientCredentialsFlow,
createHttpClient,
} = require('@commercetools/sdk-client-v2')
const { createApiBuilderFromCtpClient } = require('@commercetools/platform-sdk')
const fetch = require('node-fetch')
const HTTP_OK = 200;
const projectKey = 'YOUR_PROJECT_KEY';
const authMiddlewareOptions = {
host: 'https://auth.eu-central-1.aws.commercetools.com',
projectKey,
credentials: {
clientId: 'API_CLIENT_ID',
clientSecret: 'API_CLIENT_SECRET',
},
scopes: ['API_CLIENT_SCOPES'],
fetch,
}
const httpMiddlewareOptions = {
host: 'https://api.eu-central-1.aws.commercetools.com/',
fetch,
}
const client = new ClientBuilder()
.withProjectKey(projectKey)
.withMiddleware(createAuthForClientCredentialsFlow(authMiddlewareOptions))
.withMiddleware(createHttpClient(httpMiddlewareOptions))
.withUserAgentMiddleware()
.build()
const apiRoot = createApiBuilderFromCtpClient(client)
commercetools API を使用して、注文を取得、作成、更新するためのさまざまなメソッドを実装できます。
export module ctClient {
export async function getOrders() {
let result: any[] = [];
await apiRoot
.withProjectKey({ projectKey })
.orders()
.get()
.execute()
.then((res: any) => {
if (res.statusCode == HTTP_OK) {
result = res.body.results;
}
})
return result;
}
export async function getOrdersById(orderId: string) {
let result: any[] = [];
await apiRoot
.withProjectKey({ projectKey })
.orders()
.withOrderNumber(orderId)
.get()
.execute()
.then((res: any) => {
if (res.statusCode == HTTP_OK) {
result = res.body.results;
}
})
return result;
}
export async function getOrdersByUsername(userName: string) {
let result: any[] = [];
await apiRoot
.withProjectKey({ projectKey })
.orders()
.search()
.post({
body: { query: '{ "filter": [ { "exact": { "field": "createdBy.clientId", "value": ' + userName + ' } } ] }' }
})
.execute()
.then((res: any) => {
if (res.statusCode == HTTP_OK) {
result = res.body.results;
}
})
return result;
}
export async function createOrder(order: string) {
let result: any[] = [];
await apiRoot
.withProjectKey({ projectKey })
.orders()
.post({
body: JSON.parse(order),
})
.execute()
.then((res: any) => {
if (res.statusCode == HTTP_OK) {
result = res.body.results;
}
})
return result;
}
export async function updateOrder(orderId: string, orderUpdate: string) {
let result: any[] = [];
await apiRoot
.withProjectKey({ projectKey })
.orders()
.withOrderNumber(orderId)
.post({
body: JSON.parse(orderUpdate),
})
.execute()
.then((res: any) => {
if (res.statusCode == HTTP_OK) {
result = res.body.results;
}
})
return result;
}
}
次に、AWS リテールデモストアの注文サービスインターフェースを実装するための、commercetools API クライアントのラッパーサービスを作成します。
import * as bodyParser from "body-parser";
import * as express from "express";
import { Logger } from "../logger/logger";
import { ctClient } from "./commercetools-client";
class OrderRoutes {
public express: express.Application;
public logger: Logger;
// array to hold users
public orders: Order[];
constructor() {
this.express = express();
this.middleware();
this.routes();
this.logger = new Logger();
}
// Configure Express middleware.
private middleware(): void {
this.express.use(bodyParser.json());
this.express.use(bodyParser.urlencoded({ extended: false }));
}
private routes(): void {
// request to get all the orders
this.express.get("/all", async (req, res) => {
this.logger.info("url:::::::" + req.url);
let result = await ctClient.getOrders();
res.json(this.prepareResponse(result));
});
// request to get an order by orderId
this.express.get("/id/:orderId", async (req, res) => {
this.logger.info("url:::::::" + req.url);
let result = await ctClient.getOrdersById(req.params.orderId);
res.json(this.prepareResponse(result));
});
// request to get all the orders by userName
this.express.get("/username/:userName", async (req, res) => {
this.logger.info("url:::::::" + req.url);
let result = await ctClient.getOrdersByUsername(req.params.userName);
res.json(this.prepareResponse(result));
});
// request to create the order
this.express.post("/", async (req, res) => {
this.logger.info("url:::::::" + req.url + ":::::::body::::::" + JSON.stringify(req.body));
let result = await ctClient.createOrder(this.prepareCreateRequest(JSON.stringify(req.body)));
res.json(this.prepareResponse(result));
});
// request to create the order
this.express.options("/", async (req, res) => {
this.logger.info("url:::::::" + req.url + ":::::::body::::::" + JSON.stringify(req.body));
let result = await ctClient.createOrder(this.prepareCreateRequest(JSON.stringify(req.body)));
res.json(this.prepareResponse(result));
});
// request to update the order
this.express.put("/id/:orderId", async (req, res) => {
this.logger.info("url:::::::" + req.url + ":::::::body::::::" + JSON.stringify(req.body));
let result = await ctClient.updateOrder(req.params.orderId, this.prepareUpdateRequest(req.body));
res.json(this.prepareResponse(result));
});
// request to update the order
this.express.options("/id/:orderId", async (req, res) => {
this.logger.info("url:::::::" + req.url + ":::::::body::::::" + JSON.stringify(req.body));
let result = await ctClient.updateOrder(req.params.orderId, this.prepareUpdateRequest(req.body));
res.json(this.prepareResponse(result));
});
}
// OMITS: request and response adapter methods
[...]
}
export default new Order().express;
ラッパーサービスにメソッドを実装したら、新しい注文マイクロサービスを AWS リテールデモストアにデプロイします。ユーザーが注文すると、その注文が commercetools Merchant Center に表示されて処理されます。同様の方法で、ショッピングカートや商品などの追加の小売機能を実装できます。
commercetools を使用してヘッドレスコマースの統合プロジェクトを始めましょう
この投稿では、commercetools ソリューションを e コマースサイトのフロントエンドと統合する方法を紹介しました。ブログの Part 2 では、Amazon EventBridge 統合を使用して commercetools バックエンドによって生成されたイベントを処理するプロセスについて解説します。
ヘッドレスコマースアーキテクチャが小売ビジネスにどのように役立つかについてディスカッションをご希望の場合、あるいは commercetools を既存のヘッドレスコマースインフラストラクチャと統合するための支援が必要な場合は、AWS アカウントチームに連絡するか、Retail on AWS にアクセスしてください。
AWS パートナースポットライト
commercetools は、最新の MACH 原則(マイクロサービスベース、APIファースト、クラウドネイティブ、ヘッドレス)に基づいて構築された先進的なコマースソリューションであり、コマースソリューションと連携することで小売企業はビジネスと顧客の正確なニーズに合わせたエクスペリエンスを調整できます。
commercetools について詳細はこちらを御覧ください。
著者について
Daniele Stroppa
Daniele Stroppa は、小売業界 AWS パートナーの EMEA テクニカルリードです。小売テクノロジーのソリューションアーキテクチャと技術戦略、および AWS のコンサルティングパートナーを担当しています。AWS には 8 年間在籍しており、Amazon Elastic Compute Cloud(Amazon EC2)コンテナサービスチームとソリューションアーキテクチャチームを担当してきました。ソフトウェア開発にも情熱を注いでおり、開発者が最適なサービスを提供できるよう支援しています。
翻訳は Solutions Architect 杉中が担当しました。原文はこちらです。