jsongounmarshallingauthorize.net

Receiving unknown response body


I am implementing the Authorize.net credit card API. The API always gives me a 200 response code regardless if the transaction is successful or it is declined. But it gives the one response body for successful transaction and a different one for declined transaction.

type AuthorizeApprovedResponse struct {
    TransactionResponse struct {
        ResponseCode   string `json:"responseCode"`
        AuthCode       string `json:"authCode"`
        AvsResultCode  string `json:"avsResultCode"`
        CvvResultCode  string `json:"cvvResultCode"`
        CavvResultCode string `json:"cavvResultCode"`
        TransID        string `json:"transId"`
        RefTransID     string `json:"refTransID"`
        TransHash      string `json:"transHash"`
        TestRequest    string `json:"testRequest"`
        AccountNumber  string `json:"accountNumber"`
        AccountType    string `json:"accountType"`
        Messages       []struct {
            Code        string `json:"code"`
            Description string `json:"description"`
        } `json:"messages"`
        UserFields []struct {
            Name  string `json:"name"`
            Value string `json:"value"`
        } `json:"userFields"`
        TransHashSha2                          string `json:"transHashSha2"`
        SupplementalDataQualificationIndicator int    `json:"SupplementalDataQualificationIndicator"`
        NetworkTransID                         string `json:"networkTransId"`
    } `json:"transactionResponse"`
    RefID    string `json:"refId"`
    Messages struct {
        ResultCode string `json:"resultCode"`
        Message    []struct {
            Code string `json:"code"`
            Text string `json:"text"`
        } `json:"message"`
    } `json:"messages"`
}

type AuthorizeDeclinedResponse struct {
    TransactionResponse struct {
        ResponseCode   string `json:"responseCode"`
        AuthCode       string `json:"authCode"`
        AvsResultCode  string `json:"avsResultCode"`
        CvvResultCode  string `json:"cvvResultCode"`
        CavvResultCode string `json:"cavvResultCode"`
        TransID        string `json:"transId"`
        RefTransID     string `json:"refTransID"`
        TransHash      string `json:"transHash"`
        TestRequest    string `json:"testRequest"`
        AccountNumber  string `json:"accountNumber"`
        AccountType    string `json:"accountType"`
        Errors         []struct {
            ErrorCode string `json:"errorCode"`
            ErrorText string `json:"errorText"`
        } `json:"errors"`
        UserFields []struct {
            Name  string `json:"name"`
            Value string `json:"value"`
        } `json:"userFields"`
        TransHashSha2                          string `json:"transHashSha2"`
        SupplementalDataQualificationIndicator int    `json:"SupplementalDataQualificationIndicator"`
        NetworkTransID                         string `json:"networkTransId"`
    } `json:"transactionResponse"`
    RefID    string `json:"refId"`
    Messages struct {
        ResultCode string `json:"resultCode"`
        Message    []struct {
            Code string `json:"code"`
            Text string `json:"text"`
        } `json:"message"`
    } `json:"messages"`
}

Here is my problem, which struct to use. I was thinking of trying an interface{} and then try to cast it to a struct?

err := json.Unmarshal(b, &whichStructToUse)
    if err != nil {
        panic(err.Error())
    }

Any advice on how to Unmarshal the response when I don't know which struct to use?


Solution

  • The API always gives me a 200 response code regardless if the transaction is successful or it is declined.

    I feel your pain.

    There's only one difference between the two responses, success has Messages and failure has Errors. Combine them.

    type CommonResponse struct {
        TransactionResponse struct {
            ResponseCode   string `json:"responseCode"`
            AuthCode       string `json:"authCode"`
            AvsResultCode  string `json:"avsResultCode"`
            CvvResultCode  string `json:"cvvResultCode"`
            CavvResultCode string `json:"cavvResultCode"`
            TransID        string `json:"transId"`
            RefTransID     string `json:"refTransID"`
            TransHash      string `json:"transHash"`
            TestRequest    string `json:"testRequest"`
            AccountNumber  string `json:"accountNumber"`
            AccountType    string `json:"accountType"`
            Messages       []struct {
                Code        string `json:"code"`
                Description string `json:"description"`
            } `json:"messages"`
            Errors         []struct {
                ErrorCode string `json:"errorCode"`
                ErrorText string `json:"errorText"`
            } `json:"errors"`
            UserFields []struct {
                Name  string `json:"name"`
                Value string `json:"value"`
            } `json:"userFields"`
            TransHashSha2                          string `json:"transHashSha2"`
            SupplementalDataQualificationIndicator int    `json:"SupplementalDataQualificationIndicator"`
            NetworkTransID                         string `json:"networkTransId"`
        } `json:"transactionResponse"`
        RefID    string `json:"refId"`
        Messages struct {
            ResultCode string `json:"resultCode"`
            Message    []struct {
                Code string `json:"code"`
                Text string `json:"text"`
            } `json:"message"`
        } `json:"messages"`
    }
    

    Then use that to unmarshall and check for Errors.

        var response CommonResponse;
        json.Unmarshal([]byte(jsonString), &response)
        if len(response.Error) == 0 {
            fmt.Println("Success!")
        } else {
            fmt.Println("Error!")
        }
    

    For the more general case, you can unmarshall to a map[string]interface{}.

    var result map[string]interface{}
    json.Unmarshal([]byte(jsonString), &result)
    

    Demonstration.