中国インターネット事情

ITを中心に中国の事 もろもろ

Yahooショップ、アマゾンのEC用のAPI プログラムサンプル

Yahooショップ、アマゾンといったECサイトAPIについて調べてみた。リダイレクト用のURLにlocalhostを設定できない場合もあるようだ。BASEはダメとのこと。まあ、サーバ立てればいいのだけど。

広告用じゃなくて出店者向けのAPIのサンプル。広告向けはいっぱいあるけど出店者向けはあまりないような感じもするので。言語はDelphi

コード

unit ecapi;

interface

uses
  Winapi.Windows,System.SysUtils,System.Classes,
  IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, IdHTTP, IdIOHandler,
  IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, Vcl.StdCtrls,
  IPPeerClient, strUtils, IdCustomTCPServer,
  IdCustomHTTPServer, IdHTTPServer, IdContext, IdMultipartFormData, IdGlobal,
  IdHashSHA, IdHMAC, IdHMACSHA1, IdCoder, IdCoder3to4, IdCoderMIME, HTTPApp,
  IdHashMessageDigest;

const
  YAPIURL = 'https://circus.shopping.ecapis.jp/ShoppingWebService/V1/';
  // YAPIURL= 'https://test.circus.shopping.ecapis.jp/ShoppingWebService/V1/';
  YAUTHAPIURL = 'https://auth.login.yahoo.co.jp/yconnect/v1/token';
  YREDIRECTURL = 'http://localhost/';

type
  Tecapi = class(tobject)
  private
    FASellerId, FAToken, FAWSAccessKeyId, FASecretKey, FYSellerId, FYToken,
    FYapp_id, FYSecretKey, FAMarketplaceId,FYRefreshToken: string;
    function TextCut(s: string; cut1: string; cut2: string): string;
    function GetMD5(msg: string; code: string): string;

  public
    property YSellerId: string read FYSellerId write FYSellerId;
    property YToken: string read FYToken write FYToken;
    property YRefreshToken: string read FYRefreshToken write FYRefreshToken;
    property Yapp_id: string read FYapp_id write FYapp_id;
    property YSecretKey: string read FYSecretKey write FYSecretKey;

    property ASellerId: string read FASellerId write FASellerId;
    property AToken: string read FAToken write FAToken;
    property AWSAccessKeyId: string read FAWSAccessKeyId write FAWSAccessKeyId;
    property ASecretKey: string read FASecretKey write FASecretKey;
    property AMarketplaceId: string read FAMarketplaceId write FAMarketplaceId;

    function editItem(PostStream: TStringList): string;
    function getStock(PostStream: TStringList): string;
    function uploadItemImage(
      filepass: string): string;
    function getreftoken(refresh_token: string
      ): string;
    function gettoken(code: string): string;
    function deleteItem(
      item_code: string): string;
    function reservePublish(  mode: string;
      reserve_time: string): string;
    function getShopProductCodeList(
      query: string; types: string; sort: string; start: string;
      results: string): string;
    function getShopBrandList(query: string;
      types: string; sort: string; start: string; results: string): string;
    function getShopCategoryList(
      query: string; category_code: string; types: string; sort: string;
      start: string; results: string): string;
    function orderCount: string;
    function orderList(xml: string): string;

    function orderInfo(xml: string): string;
    function cutToken(code: string): string;
    function cutreftoken(code: string): string;

    function MwsRequest(const AFolder, AVersion: string;
      const AParams: TStringList; const AEndPoint: string): string;

    function MwsRequestFeedFlat(const AFolder, AVersion: string;
      const AParams: TStringList; const AEndPoint: string;
      postdata: string): string;

    function MwsRequestFeedXml(const AFolder, AVersion: string;
      const AParams: TStringList; const AEndPoint: string;
      postdata: string): string;

  end;

implementation

// Yahoo shop API
function Tecapi.TextCut(s: string; cut1: string; cut2: string): string;
var
  i: integer;
begin
  i := Pos(cut1, s);
  if i > 0 then
  begin
    i := i + length(cut1);
    s := copy(s, i, 10000000);
    i := Pos(cut2, s);
    result := copy(s, 1, i - 1);
  end
  else
  begin
    result := '';
  end;
end;

function Tecapi.cutToken(code: string): string;
begin
  result := TextCut(code, '"access_token":"', '"');
end;

function Tecapi.cutreftoken(code: string): string;
begin
  result := TextCut(code, 'refresh_token":"', '"');
end;

function Tecapi.editItem(PostStream: TStringList): string;
var
  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;
begin
  result := '';
  PostStream.Clear;
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);
  http := TIdHTTP.Create();
  http.ProtocolVersion := pv1_1;
  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Post(YAPIURL + 'editItem', PostStream, strm);
    strm.Position := 0;

    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    strm.Free;
  end;

end;

function Tecapi.getStock(PostStream: TStringList): string;
var

  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;

begin
  result := '';
  PostStream.Clear;
  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);
  http.ProtocolVersion := pv1_1;

  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Post(YAPIURL + 'getStock', PostStream, strm);
    strm.Position := 0;

    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    strm.Free;
  end;

end;

function Tecapi.deleteItem(
  item_code: string): string;
var

  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;

  PostStream: TStringList;
begin
  result := '';
  PostStream := TStringList.Create;
  PostStream.Clear;
  PostStream.Add('seller_id=' + FYSellerId);
  PostStream.Add('item_code=' + item_code);
  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();

  // UTF8のサイトの場合
  strm := TStringStream.Create('', TEncoding.UTF8);

  http.ProtocolVersion := pv1_1;

  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Post(YAPIURL + 'deleteItem', PostStream, strm);
    strm.Position := 0;

    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    PostStream.Free;
    strm.Free;
  end;

end;
//    PostStream.Add('seller_id=');
//    PostStream.Add('item_code=');
//    PostStream.Add('name=');
//    PostStream.Add('path=');
//    PostStream.Add('product_category=');
//    PostStream.Add('price=');
//    商品画像:商品コード.拡張子
//    商品詳細画像:商品コード_(1-5).拡張子
// http://developer.yahoo.co.jp/webapi/shopping/uploadItemImage.html


function Tecapi.uploadItemImage(
  filepass: string): string;
var

  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;

  DataStream: TIdMultiPartFormDataStream;
begin
  result := '';
  DataStream := TIdMultiPartFormDataStream.Create;
  DataStream.AddFile('file', filepass, 'multipart/form-data');

  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);
  http := TIdHTTP.Create();
  http.ProtocolVersion := pv1_1;

  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Post(YAPIURL + 'uploadItemImage?seller_id=' + FYSellerId,
      DataStream, strm);
    strm.Position := 0;

    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    strm.Free;
    DataStream.Free;

  end;

end;

function Tecapi.reservePublish(mode: string;
  reserve_time: string): string;
var

  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;

  PostStream: TStringList;
begin
  result := '';
  PostStream := TStringList.Create;
  PostStream.Clear;
  PostStream.Add('seller_id=' + FYSellerId);
  PostStream.Add('mode=' + mode);
  PostStream.Add('reserve_time=' + reserve_time);
  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);
  http.ProtocolVersion := pv1_1;

  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Post(YAPIURL + 'reservePublish', PostStream, strm);
    strm.Position := 0;
    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    PostStream.Free;
    strm.Free;
  end;

end;

function Tecapi.getShopProductCodeList(
  query: string; types: string; sort: string; start: string;
  results: string): string;
var

  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;

  gettext: string;
begin
  result := '';
  gettext := 'seller_id=' + FYSellerId + '&query=' + query + '&type=' + types +
    '&sort=' + sort + '&start=' + start + '&results=' + results;
  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);
  http.ProtocolVersion := pv1_1;

  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Get(YAPIURL + 'getShopProductCodeList?' + gettext, strm);
    strm.Position := 0;

    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    strm.Free;
  end;

end;

function Tecapi.getShopBrandList(
  query: string; types: string; sort: string; start: string;
  results: string): string;
var
  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;
  gettext: string;
begin
  result := '';
  gettext := 'seller_id=' + FYSellerId + '&query=' + query + '&type=' + types +
    '&sort=' + sort + '&start=' + start + '&results=' + results;

  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);
  http.ProtocolVersion := pv1_1;

  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Get(YAPIURL + 'getShopBrandList?' + gettext, strm);
    strm.Position := 0;

    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    strm.Free;
  end;

end;

function Tecapi.getShopCategoryList(
  query: string; category_code: string; types: string; sort: string;
  start: string; results: string): string;
var

  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;

  gettext: string;
begin
  result := '';
  gettext := 'seller_id=' + FYSellerId + '&query=' + query + '&category_code=' +
    category_code + '&type=' + types + '&sort=' + sort + '&start=' + start +
    '&results=' + results;
  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  // UTF8のサイトの場合
  strm := TStringStream.Create('', TEncoding.UTF8);
  http.ProtocolVersion := pv1_1;
  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Get(YAPIURL + 'getShopCategoryList?' + gettext, strm);
    strm.Position := 0;

    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    strm.Free;
  end;

end;

function Tecapi.orderCount: string;
var
  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;
  gettext: string;
begin
  result := '';
  gettext := 'seller_id=' + FYSellerId;

  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);
  http.ProtocolVersion := pv1_1;

  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Get(YAPIURL + 'orderCount?' + gettext, strm);
    strm.Position := 0;

    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    strm.Free;
  end;

end;

function Tecapi.orderList(xml: string): string;
var

  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;

  PostStream: TStringList;
begin
  result := '';
  PostStream := TStringList.Create;
  PostStream.Clear;
  PostStream.Add(xml);
  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);
  http.ProtocolVersion := pv1_1;

  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Post(YAPIURL + 'orderList', PostStream, strm);
    strm.Position := 0;

    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    PostStream.Free;
    strm.Free;
  end;

end;

function Tecapi.orderInfo(xml: string): string;
var

  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;

  PostStream: TStringList;
begin
  result := '';
  PostStream := TStringList.Create;
  PostStream.Clear;
  PostStream.Add(xml);
  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);
  http.ProtocolVersion := pv1_1;

  try
    http.IOHandler := ssl;
    http.Request.CustomHeaders.FoldLines := False;
    http.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FYToken);
    http.Post(YAPIURL + 'orderInfo', PostStream, strm);
    strm.Position := 0;
    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    PostStream.Free;
    strm.Free;
  end;

end;



// トークン関係
//ログインしないとトークンを取得するためのcodeが取得できない 
//https://auth.login.yahoo.co.jp/yconnect/v1/authorizatione=
//

//リフレッシュトークンからトークン取得
function Tecapi.getreftoken(refresh_token: string
  ): string;
var
  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;
  PostStream: TStringList;

begin
  result := '';
  PostStream := TStringList.Create;
  PostStream.Clear;
  PostStream.Add('grant_type=refresh_token');
  PostStream.Add('refresh_token=' + refresh_token);
  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);

  try
    http.IOHandler := ssl;
    http.Request.BasicAuthentication := true;
    http.HandleRedirects := true;
    http.Request.Username := Yapp_id;
    http.Request.Password := YSecretKey;
    http.Post(YAUTHAPIURL, PostStream, strm);
    strm.Position := 0;
    result := strm.DataString;
    self.FYToken :=  cuttoken(strm.DataString);

  finally
    http.Free;
    ssl.Free;
    strm.Free;
    PostStream.Free;
  end;

end;

//トークン取得プロパティにも投入
function Tecapi.gettoken(code: string): string;
var
  http: TIdHTTP;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  strm: TStringStream;
  PostStream: TStringList;
begin
  result := '';
  PostStream := TStringList.Create;
  PostStream.Clear;
  PostStream.Add('grant_type=authorization_code');
  PostStream.Add('code=' + code);
  PostStream.Add('redirect_uri=' + YREDIRECTURL);

  http := TIdHTTP.Create();
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
  strm := TStringStream.Create('', TEncoding.UTF8);

  try
    http.IOHandler := ssl;
    http.Request.BasicAuthentication := true;
    http.HandleRedirects := true;
    http.Request.Username := Yapp_id;
    http.Request.Password := YSecretKey;
    http.Post(YAUTHAPIURL, PostStream, strm);
    strm.Position := 0;
    self.FYToken :=  cuttoken(strm.DataString);
    FYRefreshToken := cutreftoken(strm.DataString);
    // 取得したハイパーテキストを出力
    result := strm.DataString;

  finally
    http.Free;
    ssl.Free;
    strm.Free;
    PostStream.Free;
  end;

end;



// Amazon MWS API
//
//http://services.amazon.co.jp/services/automation/for-developer.html
//https://mws.amazonservices.jp/scratchpad/index.html
//
//AParamsにコマンドを投入する
//

function Tecapi.GetMD5(msg: string; code: string): string;
var
  md5: TIdHashMessageDigest5;
begin
  md5 := TIdHashMessageDigest5.Create;

  //MD5文字コードを合わせないとエラーが発生
  try
    result := TIdEncoderMIME.EncodeBytes
      (md5.HashBytes(TIdBytes(TEncoding.UTF8.GetBytes(msg))));

    if code = 'ASCII' then
    begin
      result := TIdEncoderMIME.EncodeBytes
        (md5.HashBytes(TIdBytes(TEncoding.ASCII.GetBytes(msg))));
    end
    else if code = 'ANSI' then
    begin
      result := TIdEncoderMIME.EncodeBytes
        (md5.HashBytes(TIdBytes(TEncoding.ANSI.GetBytes(msg))));
    end;

  finally
    md5.Free;
  end;
end;

function CustomSortASC(List: TStringList; Index1, Index2: integer): integer;
// 昇順ソート
begin
  // result := AnsiCompareStr(List[Index1], List[Index2]); // ロケール考慮/大文字小文字区別
  result := CompareStr(List[Index1], List[Index2]); // ロケール無視/大文字小文字区別
  // result := AnsiCompareText(List[Index1], List[Index2]); // ロケール考慮/大文字小文字無視
  // result := CompareText(List[Index1], List[Index2]); // ロケール無視/大文字小文字無視
end;

// アマゾンへのアクセス
function Tecapi.MwsRequest(const AFolder, AVersion: string;
  const AParams: TStringList; const AEndPoint: string): string;
var
  i: integer;
  sl: TStringList;
  AMethod, AHost, AURI, ARequest, AStrToSign, APath, ASignature: string;
  AKey, AValue, AQuery: string;
  AHTTP: TIdHTTP;
  AStream, AResultStream: TStringStream;
  UTC: TSystemTime;
  dt: Tdatetime;

  function urlencode_rfc3986(str: string): string;
  begin
    result := replacetext(Httpencode(str), '%7E', '~');
    result := replacetext(result, '+', '%20');
  end;

  function GenerateSignature(const AData, AKey: string): string;
  var
    AHMAC: TIdBytes;
  begin
    IdSSLOpenSSL.LoadOpenSSLLibrary;

    IF NOT TIdHashSHA256.IsAvailable THEN
      Raise Exception.Create('SHA-256 hashing is not available!');

    With TIdHMACSHA256.Create do
      try
        Key := IndyTextEncoding_UTF8.GetBytes(AKey);
        AHMAC := HashValue(IndyTextEncoding_UTF8.GetBytes(AData));
      finally
        Free;
      end;
    result := TIdEncoderMIME.EncodeBytes(AHMAC);
  end;

begin
  AMethod := 'POST';
  AHost := AEndPoint;
  AURI := '/' + AFolder + '/' + AVersion;

  AQuery := '';
  sl := TStringList.Create;
  try
    sl.Assign(AParams);
    sl.Values['SignatureMethod'] := 'HmacSHA256';
    sl.Values['SignatureVersion'] := '2';
    sl.Values['SellerId'] := FASellerId;
    sl.Values['AWSAccessKeyId'] := FAWSAccessKeyId;
    sl.Values['MarketplaceId'] := FAMarketplaceId;

    // UTCでないとエラーになる
    GetSystemTime(UTC);

    // タイムスタンプの後にはZが必要
    dt := SystemTimeToDateTime(UTC);
    sl.Values['Timestamp'] := FormatDateTime('YYYY-MM-DD"T"HH:NN:SS"Z"', dt);
    sl.Values['Version'] := AVersion;

    // 確実にソートしないとエラーになる
    sl.CustomSort(CustomSortASC);

    FOR i := 0 TO sl.Count - 1 DO
    begin
      AKey := urlencode_rfc3986(sl.Names[i]);
      AValue := urlencode_rfc3986(sl.ValueFromIndex[i]);
      sl[i] := AKey + '=' + AValue;
    end;

    sl.StrictDelimiter := true;
    sl.Delimiter := '&';
    sl.QuoteChar := #0;
    AQuery := sl.DelimitedText;

    AStrToSign := AMethod + #10 + Lowercase(AHost) + #10 + AURI + #10 + AQuery;
    ASignature := GenerateSignature(AStrToSign, FASecretKey);
    APath := 'https://' + AHost + AURI + '?' + AQuery + '&Signature=' +
      urlencode_rfc3986(ASignature);

  finally
    sl.Free;
  end;

  AHTTP := TIdHTTP.Create(nil);
  try
    AHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(AHTTP);
    AHTTP.Request.ContentType := 'text/xml; charset=UTF-8';
    AHTTP.Request.Connection := 'Close';
    AHTTP.Request.CustomHeaders.Add
      ('x-amazon-user-agent: MyApp/1.0 (Language=Delphi)');
    AHTTP.HTTPOptions := AHTTP.HTTPOptions + [hoKeepOrigProtocol];
    AHTTP.HTTPOptions := AHTTP.HTTPOptions - [hoForceEncodeParams];
    AHTTP.ProtocolVersion := pv1_1;

    AStream := TStringStream.Create;
    AResultStream := TStringStream.Create('', TEncoding.UTF8);
    try
      AHTTP.Post(APath, AStream, AResultStream);
      result := AResultStream.DataString;
    finally
      AStream.Free;
      AResultStream.Free;
    end;
  finally
    AHTTP.Free;
  end;
end;


//FeedType
//https://docs.developer.amazonservices.com/en_US/feeds/Feeds_FeedType.html
//_POST_FLAT_FILE_FULFILLMENT_DATA_ 出荷通知
//http://aws.typepad.com/jp_mws/2011/07/amazon-mws-order-fulfillment-feed.html
//https://docs.developer.amazonservices.com/ja_JP/feeds/Feeds_FeedType.html


function Tecapi.MwsRequestFeedFlat(const AFolder, AVersion: string;
  const AParams: TStringList; const AEndPoint: string;
  postdata: string): string;
var
  i: integer;
  sl: TStringList;
  AMethod, AHost, AURI, ARequest, AStrToSign, APath, ASignature: string;
  AKey, AValue, AQuery: string;
  AHTTP: TIdHTTP;
  AStream, AResultStream: TStringStream;
  UTC: TSystemTime;
  dt: Tdatetime;
  naiyou: ansistring;

  function urlencode_rfc3986(str: string): string;
  begin
    result := replacetext(Httpencode(str), '%7E', '~');
    result := replacetext(result, '+', '%20');
  end;

  function GenerateSignature(const AData, AKey: string): string;
  var
    AHMAC: TIdBytes;
  begin
    IdSSLOpenSSL.LoadOpenSSLLibrary;

    IF NOT TIdHashSHA256.IsAvailable THEN
      Raise Exception.Create('SHA-256 hashing is not available!');

    With TIdHMACSHA256.Create do
      try
        Key := IndyTextEncoding_UTF8.GetBytes(AKey);
        AHMAC := HashValue(IndyTextEncoding_UTF8.GetBytes(AData));
      finally
        Free;
      end;
    result := TIdEncoderMIME.EncodeBytes(AHMAC);
  end;

begin
  AMethod := 'POST';
  AHost := AEndPoint;
  AURI := '/' + AFolder + '/' + AVersion;
  AQuery := '';
  AStream := TStringStream.Create('', TEncoding.GetEncoding(932));
  AStream.WriteString(postdata);

  sl := TStringList.Create;
  try
    sl.Assign(AParams);
    sl.Values['SignatureMethod'] := 'HmacSHA256';
    sl.Values['SignatureVersion'] := '2';
    GetSystemTime(UTC);
    dt := SystemTimeToDateTime(UTC);
    sl.Values['Timestamp'] := FormatDateTime('YYYY-MM-DD"T"HH:NN:SS"Z"', dt);
    sl.Values['Version'] := AVersion;
    sl.Values['ContentMD5Value'] := GetMD5(AStream.DataString, 'ANSI');
    sl.Values['SellerId'] := FASellerId;
    sl.Values['AWSAccessKeyId'] := FAWSAccessKeyId;
    sl.Values['MarketplaceId'] := FAMarketplaceId;

    // 確実にソートする
    sl.CustomSort(CustomSortASC);

    for i := 0 to sl.Count - 1 do
    begin
      AKey := urlencode_rfc3986(sl.Names[i]);
      AValue := urlencode_rfc3986(sl.ValueFromIndex[i]);
      sl[i] := AKey + '=' + AValue;
    end;

    sl.StrictDelimiter := true;
    sl.Delimiter := '&';
    sl.QuoteChar := #0;
    AQuery := sl.DelimitedText;

    AStrToSign := AMethod + #10 + Lowercase(AHost) + #10 + AURI + #10 + AQuery;
    ASignature := GenerateSignature(AStrToSign, FASecretKey);
    APath := 'https://' + AHost + AURI + '?' + AQuery + '&Signature=' +
      urlencode_rfc3986(ASignature);

  finally
    sl.Free;
  end;

  AHTTP := TIdHTTP.Create(nil);
  try
    AHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(AHTTP);
    AHTTP.Request.ContentType := 'text/xml; charset=UTF-8';
    AHTTP.Request.Connection := 'Close';
    AHTTP.Request.CustomHeaders.Add
      ('x-amazon-user-agent: MyApp/1.0 (Language=Delphi)');
    AHTTP.Request.CustomHeaders.Add
    // ('text/tab-separated-values; charset=UTF-8');
      ('text/tab-separated-values; charset=Shift_JIS');
    AHTTP.HTTPOptions := AHTTP.HTTPOptions + [hoKeepOrigProtocol];
    AHTTP.HTTPOptions := AHTTP.HTTPOptions - [hoForceEncodeParams];
    AHTTP.ProtocolVersion := pv1_1;
    AResultStream := TStringStream.Create('', TEncoding.UTF8);
    try
      try
        AHTTP.Post(APath, AStream, AResultStream);
      except
      end;

      result := AResultStream.DataString;
    finally
      AStream.Free;
      AResultStream.Free;
    end;
  finally
    AHTTP.Free;
  end;
end;

function Tecapi.MwsRequestFeedXml(const AFolder, AVersion: string;
  const AParams: TStringList; const AEndPoint: string;
  postdata: string): string;
var
  i: integer;
  sl: TStringList;
  AMethod, AHost, AURI, ARequest, AStrToSign, APath, ASignature: string;
  AKey, AValue, AQuery: string;
  AHTTP: TIdHTTP;
  AStream, AResultStream: TStringStream;
  UTC: TSystemTime;
  dt: Tdatetime;
  naiyou: ansistring;

  function urlencode_rfc3986(str: string): string;
  begin
    result := replacetext(Httpencode(str), '%7E', '~');
    result := replacetext(result, '+', '%20');
  end;

  function GenerateSignature(const AData, AKey: string): string;
  var
    AHMAC: TIdBytes;
  begin
    IdSSLOpenSSL.LoadOpenSSLLibrary;

    IF NOT TIdHashSHA256.IsAvailable THEN
      Raise Exception.Create('SHA-256 hashing is not available!');

    With TIdHMACSHA256.Create do
      try
        Key := IndyTextEncoding_UTF8.GetBytes(AKey);
        AHMAC := HashValue(IndyTextEncoding_UTF8.GetBytes(AData));
      finally
        Free;
      end;
    result := TIdEncoderMIME.EncodeBytes(AHMAC);
  end;

begin
  AMethod := 'POST';
  AHost := AEndPoint;
  AURI := '/' + AFolder + '/' + AVersion;
  AQuery := '';

  AStream := TStringStream.Create('', TEncoding.UTF8);
  AStream.WriteString(postdata);

  sl := TStringList.Create;
  try
    sl.Assign(AParams);
    sl.Values['SignatureMethod'] := 'HmacSHA256';
    sl.Values['SignatureVersion'] := '2';
    GetSystemTime(UTC);
    dt := SystemTimeToDateTime(UTC);
    sl.Values['Timestamp'] := FormatDateTime('YYYY-MM-DD"T"HH:NN:SS"Z"', dt);
    sl.Values['Version'] := AVersion;
    sl.Values['ContentMD5Value'] := GetMD5(AStream.DataString, '');
    sl.Values['SellerId'] := FASellerId;
    sl.Values['AWSAccessKeyId'] := FAWSAccessKeyId;
    sl.Values['MarketplaceId'] := FAMarketplaceId;

    // 確実にソートする
    sl.CustomSort(CustomSortASC);

    for i := 0 to sl.Count - 1 do
    begin
      AKey := urlencode_rfc3986(sl.Names[i]);
      AValue := urlencode_rfc3986(sl.ValueFromIndex[i]);
      sl[i] := AKey + '=' + AValue;
    end;

    sl.StrictDelimiter := true;
    sl.Delimiter := '&';
    sl.QuoteChar := #0;
    AQuery := sl.DelimitedText;

    AStrToSign := AMethod + #10 + Lowercase(AHost) + #10 + AURI + #10 + AQuery;
    ASignature := GenerateSignature(AStrToSign, FASecretKey);
    APath := 'https://' + AHost + AURI + '?' + AQuery + '&Signature=' +
      urlencode_rfc3986(ASignature);

  finally
    sl.Free;
  end;

  AHTTP := TIdHTTP.Create(nil);
  try

    AHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(AHTTP);
    AHTTP.Request.ContentType := 'text/xml; charset=UTF-8';
    AHTTP.Request.Connection := 'Close';
    AHTTP.Request.CustomHeaders.Add
      ('x-amazon-user-agent: MyApp/1.0 (Language=Delphi)');
    AHTTP.Request.CustomHeaders.Add('text/tab-separated-values; charset=UTF-8');
    // ('text/tab-separated-values; charset=Shift_JIS');
    AHTTP.HTTPOptions := AHTTP.HTTPOptions + [hoKeepOrigProtocol];
    AHTTP.HTTPOptions := AHTTP.HTTPOptions - [hoForceEncodeParams];
    AHTTP.ProtocolVersion := pv1_1;
    AResultStream := TStringStream.Create('', TEncoding.UTF8);
    try
      try
        AHTTP.Post(APath, AStream, AResultStream);
      except
      end;
      result := AResultStream.DataString;
    finally
      AStream.Free;
      AResultStream.Free;
    end;
  finally
    AHTTP.Free;
  end;
end;

end.