Shopify x Amazon連携に関してまとめていきます。 商品データ連携、注文データ連携、在庫データ連携、配送データ連携をカバーしていきます。
本日はまず、
Shopifyの商品情報をAmazonにプッシュする方法をカバーします。
長くなるので2部に分けました。まずは、前半を公開します。前半ではShopifyで商品情報が更新された最にWebhookで受け取るところから始まります。 下記がイメージです。
事前に準備するもの
- Shopifyアカウント
- Amazon MWS アカウント
- Azure アカウント
- Visual Studio
ShopifyのWebhookを受け取る
まずはShopify上で商品情報に変更がある際にWebhook
で更新された内容を探知します。
そのためにAzure Functions
を用意します。Azure Functions
の用意に関しては下記を参照ください。
https://qiita.com/syantien/items/ab62db3b5ccec230db4e
Webhook
に関してはShopifyにあるこちらのドキュメントをベースに進めていきます
https://help.shopify.com/en/api/getting-started/webhooks
ShopifyでWebhook
の購読を設定
メニュー右下の「設定」をクリック、設定メニューの「通知」をクリックしてください。
通知設定画面の一番下部分に「Webhookを作成」ボタンがあるのでクリック。
次にWebhook
の内容を選択し、それを受信するURL
を入力します。
今回は商品の更新がある度にAmazonでも該当する商品の更新を行うので「商品更新」を指定します。
Webhook
が作成されると、下記のように表示されます。ここ(①)に表記されるURL
が正しいことを確認し、下部分にある文字列(②)を使い、正しいWebhook
であることを確認します。
こちらのドキュメントによるとヘッダーで下記の値が渡されるとのことです。
X-Shopify-Topic: orders/create
X-Shopify-Hmac-Sha256: XWmrwMey6OsLMeiZKwP4FppHH3cmAiiJJAweH5Jo4bM=
X-Shopify-Shop-Domain: johns-apparel.myshopify.com
X-Shopify-API-Version: 2019-04
X-Shopify-Topic
で正しいトピックか確認、X-Shopify-Hmac-Sha256
で②にあった文字列を使いSha256で暗号化された文字列が正しいか確認、X-Shopify-Shop-Domain
で対象のストアーであることを確認、X-Shopify-API-Version
でAPIのバージョンを確認してください。
Webhook
レスポンスクラスの定義
products/create
またはproducts/update
の際のレスポンス型は下記です。
{
"id": 788032119674292922,
"title": "Example T-Shirt",
"body_html": null,
"vendor": "Acme",
"product_type": "Shirts",
"created_at": null,
"handle": "example-t-shirt",
"updated_at": null,
"published_at": "2019-12-18T12:06:06-05:00",
"template_suffix": null,
"tags": "example, mens, t-shirt",
"published_scope": "web",
"variants": [
{
"id": 642667041472713922,
"product_id": 788032119674292922,
"title": "",
"price": "19.99",
"sku": "example-shirt-s",
"position": 0,
"inventory_policy": "deny",
"compare_at_price": "24.99",
"fulfillment_service": "manual",
"inventory_management": "shopify",
"option1": "Small",
"option2": null,
"option3": null,
"created_at": null,
"updated_at": null,
"taxable": true,
"barcode": null,
"grams": 200,
"image_id": null,
"weight": 200.0,
"weight_unit": "g",
"inventory_item_id": null,
"inventory_quantity": 75,
"old_inventory_quantity": 75,
"requires_shipping": true
},
{
"id": 757650484644203962,
"product_id": 788032119674292922,
"title": "",
"price": "19.99",
"sku": "example-shirt-m",
"position": 0,
"inventory_policy": "deny",
"compare_at_price": "24.99",
"fulfillment_service": "manual",
"inventory_management": "shopify",
"option1": "Medium",
"option2": null,
"option3": null,
"created_at": null,
"updated_at": null,
"taxable": true,
"barcode": null,
"grams": 200,
"image_id": null,
"weight": 200.0,
"weight_unit": "g",
"inventory_item_id": null,
"inventory_quantity": 50,
"old_inventory_quantity": 50,
"requires_shipping": true
}
],
"options": [
{
"id": 527050010214937811,
"product_id": 788032119674292922,
"name": "Title",
"position": 1,
"values": [
"Small",
"Medium"
]
}
],
"images": [
{
"id": 539438707724640965,
"product_id": 788032119674292922,
"position": 0,
"created_at": null,
"updated_at": null,
"alt": null,
"width": 323,
"height": 434,
"src": "\/\/cdn.shopify.com\/s\/assets\/shopify_shirt-39bb555874ecaeed0a1170417d58bbcf792f7ceb56acfe758384f788710ba635.png",
"variant_ids": [
]
}
],
"image": null
}
ここで一つ、Visual Studioでのやばいテクニックを紹介。上記のサンプルJsonをコピーします。このJsonファイルのモデルを定義したいクラスファイルを開き、Visual Studioの「編集」→「形式を選択して貼り付け」→JSONクラスとして貼り付けるをクリック。
クリック後、下記のようなモデルが自動で生成されます。
public class Rootobject
{
public long id { get; set; }
public string title { get; set; }
public object body_html { get; set; }
public string vendor { get; set; }
public string product_type { get; set; }
public object created_at { get; set; }
public string handle { get; set; }
public object updated_at { get; set; }
public DateTime published_at { get; set; }
public object template_suffix { get; set; }
public string tags { get; set; }
public string published_scope { get; set; }
public Variant[] variants { get; set; }
public Option[] options { get; set; }
public Image[] images { get; set; }
public object image { get; set; }
}
public class Variant
{
public long id { get; set; }
public long product_id { get; set; }
public string title { get; set; }
public string price { get; set; }
public string sku { get; set; }
public int position { get; set; }
public string inventory_policy { get; set; }
public string compare_at_price { get; set; }
public string fulfillment_service { get; set; }
public string inventory_management { get; set; }
public string option1 { get; set; }
public object option2 { get; set; }
public object option3 { get; set; }
public object created_at { get; set; }
public object updated_at { get; set; }
public bool taxable { get; set; }
public object barcode { get; set; }
public int grams { get; set; }
public object image_id { get; set; }
public float weight { get; set; }
public string weight_unit { get; set; }
public object inventory_item_id { get; set; }
public int inventory_quantity { get; set; }
public int old_inventory_quantity { get; set; }
public bool requires_shipping { get; set; }
}
public class Option
{
public long id { get; set; }
public long product_id { get; set; }
public string name { get; set; }
public int position { get; set; }
public string[] values { get; set; }
}
public class Image
{
public long id { get; set; }
public long product_id { get; set; }
public int position { get; set; }
public object created_at { get; set; }
public object updated_at { get; set; }
public object alt { get; set; }
public int width { get; set; }
public int height { get; set; }
public string src { get; set; }
public object[] variant_ids { get; set; }
}
ということで、Shopify Webhook
(Product/Create Product/Update)のJsonを受けるC#モデルは上記です。
Webhook
を受けるFunction
では、さっそくFunctionもこのデータを受け取るようにします。
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using ShopifyWebhookHandler.Models;
using System.Text;
using System.Security.Cryptography;
namespace ShopifyWebhookHandler
{
public class ShopifyWebHookHandlerProductUpdateHandler
{
private string _sharedSecret = "Your Key Here";
[FunctionName("ShopifyWebHookHandlerProductUpdateHandler")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("Hello? Did you call me?");
// Read all
req.Headers.TryGetValue("X-Shopify-Topic", out var topic);
req.Headers.TryGetValue("X-Shopify-Hmac-Sha256", out var hMacSha256);
req.Headers.TryGetValue("X-Shopify-Shop-Domain", out var domain);
req.Headers.TryGetValue("X-Shopify-API-Version", out var apiVersion);
string requestBody = await new StreamReader(req.Body,Encoding.UTF8).ReadToEndAsync();
if (topic != "")
{
// do something if it's not the tipc you are looking for
log.LogInformation("Topic was: " + topic );
}
var keyBytes = Encoding.UTF8.GetBytes(_sharedSecret);
var dataBytes = Encoding.UTF8.GetBytes(requestBody);
var hmac = new HMACSHA256(keyBytes);
var hmacBytes = hmac.ComputeHash(dataBytes);
var createSignature = Convert.ToBase64String(hmacBytes);
if (hMacSha256 == createSignature)
{
// do something if key does not match
}
log.LogInformation("I compare " + hMacSha256 + " vs " + createSignature);
if (domain != "")
{
// do something if it's not the domain you are looking for
log.LogInformation("Domain was: " + domain);
}
// Map data into ProductModel
var data = JsonConvert.DeserializeObject<ProductModel>(requestBody);
log.LogInformation("The product " + data.title + " was updated. Api version is " + apiVersion + ".");
return data != null
? (ActionResult)new OkObjectResult("Good news, all good.")
: new BadRequestObjectResult("Bad news, I got NULL.");
}
private string sha256(string randomString)
{
var crypt = new System.Security.Cryptography.SHA256Managed();
var hash = new System.Text.StringBuilder();
byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(randomString));
foreach (byte theByte in crypto)
{
hash.Append(theByte.ToString("x2"));
}
return hash.ToString();
}
}
}
ではさっそくテストをしてみます。テストは先ほどの管理画面右側から送ることができます。
そして下記がFunctionsのLogになります。
X-Shopify-Hmac-Sha256
もちゃんと照合することができました。
次
次はAmzazon API を使って商品情報をプッシュします。