饿了么 OpenAPI 2.0 を活用した注文同期システムの構築

概要

従来の饿了么(Ele.me)OpenAPI では、店舗をバインドする際にメールによる申請が必要であり、処理に時間を要する課題がありました。しかし、OpenAPI 2.0 のリリースにより、OAuth 2.0 標準プロトコルを採用した自助式の認証フローが可能になりました。これにより、開発者と店舗側だけで完結する迅速な連携が実現します。本稿では、.NET 環境において饿了么 OpenAPI 2.0 を統合し、注文データを同期する具体的な実装手順について解説します。

開発環境のセットアップ

まず、饿了么開放平台 にアクセスし、開発者として登録を行います。登録後、開発者資格認証を行い、必要な情報を提出して審査を待ちます。審査通過後、開発者センターにてアプリケーションを作成します。

アプリケーション作成後は、サンドボックス環境の設定を行います。主な設定項目は以下の通りです。

  • コールバック URL: 店舗授权後のリダイレクト先
  • プッシュ URL: 新注文やステータス変更などの通知受信エンドポイント
  • 通知タイプ: 受信が必要なメッセージ種類の選択

これらの設定が完了すれば、コード実装に移ることができます。

OAuth 2.0 による店舗認証の実装

饿了么 OpenAPI 2.0 では、国際標準の OAuth 2.0 プロトコルを用いて店舗の認証と授权を行います。.NET 向けの公式 SDK は提供されていないため、HTTP リクエストを直接構築して実装する必要があります。

認証フローの核心となるクラス実装例を以下に示します。ここでは、認証 URL の生成とアクセストークンの取得処理を実装しています。

public class ElemeOAuthService
{
    private readonly HttpRequest _request;
    private readonly ConfigSettings _config;

    public ElemeOAuthService(HttpRequest request, ConfigSettings config)
    {
        _request = request;
        _config = config;
    }

    /// <summary>
    /// 認証用 URL の構築
    /// </summary>
    public string ConstructAuthEndpoint(int merchantId)
    {
        var redirectUri = HttpUtility.UrlEncode(_config.AuthCallbackUrl);
        var queryParams = $"response_type=code&client_id={_config.AppKey}&redirect_uri={redirectUri}&state={merchantId}&scope=all";
        return $"{_config.AuthBaseUrl}?{queryParams}";
    }

    /// <summary>
    /// アクセストークンの取得
    /// </summary>
    public AccessTokenResponse FetchToken()
    {
        var code = _request.Params["code"];
        var state = _request.Params["state"];
        
        var authHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_config.AppKey}:{_config.AppSecret}"));
        
        var httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authHeader);

        var content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("grant_type", "authorization_code"),
            new KeyValuePair<string, string>("code", code),
            new KeyValuePair<string, string>("redirect_uri", _config.AuthCallbackUrl),
            new KeyValuePair<string, string>("client_id", _config.AppKey)
        });

        var response = httpClient.PostAsync(_config.TokenUrl, content).Result;
        var jsonString = response.Content.ReadAsStringAsync().Result;
        
        var tokenInfo = JsonConvert.DeserializeObject<AccessTokenResponse>(jsonString);
        if (tokenInfo != null)
        {
            tokenInfo.MerchantId = Convert.ToInt32(state);
        }
        return tokenInfo;
    }
}

実装時の注意点として、トークン取得リクエストの HTTP ヘッダーには、Authorization フィールドが必要です。この値は、app_keyapp_secret をコロンで連結した文字列を Base64 エンコードしたもので構成されます(例:Basic base64(key:secret))。

署名アルゴリズムの実装

API リクエストには署名が必要であり、これが実装において最も注意を要する部分です。署名生成のロジックは独自仕様が含まれているため、ドキュメント仕様に厳密に従う必要があります。

主なポイントは以下の通りです。

  1. 署名対象のパラメータは、JSON オブジェクト内の metas および params 属性のみを含みます。
  2. パラメータの結合は key=json_encode(value) 形式で行います。データ型(数値と文字列)によって JSON エンコード後の表現が異なるため、型変換に注意が必要です。
  3. 結合後の文字列はソートされ、actiontokensecret と連結された後、MD5 ハッシュ化されます。

署名生成メソッドの実装例は以下の通りです。

public string ComputeSignatureHash(string action, string accessToken)
{
    var sortedParams = new StringBuilder();
    var paramList = _signatureParams.Keys.OrderBy(k => k).ToList();

    foreach (var key in paramList)
    {
        var value = JsonConvert.SerializeObject(_signatureParams[key]);
        sortedParams.Append($"{key}={value}");
    }

    var rawString = $"{action}{accessToken}{sortedParams.ToString()}{_config.AppSecret}";
    var hashBytes = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(rawString));
    
    var sb = new StringBuilder();
    foreach (var b in hashBytes)
    {
        sb.Append(b.ToString("X2"));
    }
    return sb.ToString().ToUpper();
}

API リクエストを送信する際は、Content-Typeapplication/json;charset=utf-8 に設定し、id パラメータには GUID を生成して使用します。POST データはハッシュテーブル等に保存されたパラメータを JSON シリアライズして送信します。

注文通知の受信と処理

サンドボックス環境で設定したプッシュ URL に対して、饿了么 サーバーから注文ステータスの変更通知が HTTP POST で送信されます。通知本体はストリーム形式で送信されるため、リクエストストリームから読み取る必要があります。

テスト環境では、商品価格が 0.1 元の場合、刷单(注文の水増し)と判定され自動的にキャンセルされる仕様があります。正常にテストを行うためには、商品価格を 1 元以上に設定する必要があります。

通知受信ハンドラーの実装例を示します。

public void HandlePushNotification()
{
    var stream = HttpContext.Current.Request.InputStream;
    if (stream == null || stream.Length <= 10) return;

    string jsonPayload;
    using (var reader = new StreamReader(stream))
    {
        jsonPayload = reader.ReadToEnd();
    }

    var notification = JsonConvert.DeserializeObject<PushNotification>(jsonPayload);

    switch (notification.Type)
    {
        case 12: // 新注文
            ProcessNewOrder(notification);
            break;
        case 14:
        case 15:
        case 17:
        case 23:
        case 25:
        case 35: // 注文キャンセル系
            ProcessCancelOrder(notification);
            break;
        default:
            break;
    }
}

private void ProcessCancelOrder(PushNotification notice)
{
    var orderData = JsonConvert.DeserializeObject<OrderDetail>(notice.Message);
    var systemOrderId = "e" + orderData.OrderId;
    
    // システム内の注文ステータスを更新
    var sql = $"UPDATE Custorder SET OrderStatus=5 WHERE OrderID='{systemOrderId}'";
    DatabaseUtility.Execute(sql);
}

本番環境への移行

サンドボックス環境での動作確認が完了したら、本番環境用のパラメータを設定し、プラットフォーム側で審査申請を行います。承認されれば、実際の注文データがシステムに同期されるようになります。

同期された注文は、既存の配送スケジューリングシステムと連携させることで、配送員への自動割り当てや配車最適化など、業務効率化のための次のステップへ進むことが可能です。

タグ: 饿了么,OpenAPI OAuth2 C# Webhook 注文同期

6月20日 21:23 投稿