bchavez / Coinbase

:moneybag: A .NET/C# implementation of the Coinbase API.
https://developers.coinbase.com/api/v2
MIT License
170 stars 92 forks source link

Access to the Raw response from the API #55

Closed granthoff1107 closed 5 years ago

granthoff1107 commented 5 years ago

There is no way to access the request made by the api. e.g if I would like to obtain the response code and the Errors it difficult. e.g

If I were to make a request to obtain send money:

var resp = await this._coinbaseOAuthClient.AllowAnyHttpStatus()
                        .WithHeader("CB-2FA-TOKEN", paymentTransaction.TwoFactorCode)
                        .AllowAnyHttpStatus()
                                    .Transactions
                                    .SendMoneyAsync(paymentTransaction.AccountId, transaction);

The response returns a 402 requires payment. But if I allow any http status I'm not sure of a way to obtain the response or have access to the raw request.

If I were to wrap not allow any httpstatus:

try{
    var resp = await this._coinbaseOAuthClient.AllowAnyHttpStatus()
                        .WithHeader("CB-2FA-TOKEN", paymentTransaction.TwoFactorCode)
                        .AllowAnyHttpStatus()
                                    .Transactions
                                    .SendMoneyAsync(paymentTransaction.AccountId, transaction);
}
catch (FlurlHttpException ex) {

}

There's no easy way to obtain the error inside of the response.

bchavez commented 5 years ago
granthoff1107 commented 5 years ago

I cant post the trace it has too much sensitive data. But what I'm trying to say is that if you allow any httpstatus code wont have any access to the request,  because we only return the data returned by the request.If you allow flurl to throw the exception will contain the request being made inside of it.  In most cases you should be able to determine the error from the errors property.But if for some reason there is an with no errors property you will have no idea what occured,E.g 500 or rate limit etc.Sent from my Samsung Galaxy smartphone.

bchavez commented 5 years ago

Hi Grant,

You can also replace the sensitive data with random data and post it here. Or, additionally, you can send it privately to my email. I just need some general idea and context of the HTTP interaction with the code to better understand the problem with the request/response mechanism; ideally, so I can write a unit test.

I don't usually like changing code unless I understand 100% the reasons why I'm changing it. Unfortunately, I'm reading what you're saying but I cannot translate English words into any actual debug session and provide solutions without seeing the HTTP transport mechanisms in play to reproduce the same feeling of frustration you're encountering.

As a work around, perhaps you can inherit from CoinbaseApi and instead do the interaction manually:

https://github.com/bchavez/Coinbase/blob/34946ddf75000cf6d2cc9007a090737d41d561ff/Source/Coinbase/CoinbaseClient.Transactions.cs#L94-L98

Also, this might help breaking up the request in piecemeal steps: https://stackoverflow.com/questions/43488710/getting-response-header/53514668#53514668

Let me know.

granthoff1107 commented 5 years ago

Sorry for the confusion, to simplify how do how do you get the httpstatuscode the coinbase wrapper doesn't contain the responseSent from my Samsung Galaxy smartphone.

bchavez commented 5 years ago

Hey Grant,

If you want the status code, I don't think there's two ways about it. I think you'll have to split up the call and do things manually as shown below:

var client = new CoinbaseClient();
var accountId = "aaa";
var txn = new CreateTransaction();

var task = this.client.Config.ApiUrl
   .AppendPathSegments("accounts", accountId, "transactions")
   .WithClient(client)
   .PostJsonAsync(txn);

var response = await task;

var httpCode = response.StatusCode;

var model = await task.ReceiveJson<Response<Transaction>>();
granthoff1107 commented 5 years ago

Thanks, maybe in future versions we could store the http call in the wrapper.  I haven't come across a time when I 100 percent need it, but for certain things I'd rather rely on httostatus code rather than parsing the errorsSent from my Samsung Galaxy smartphone.

bchavez commented 5 years ago

Here's another way to do it:

var accountId = "aaa";
var txn = new CreateTransaction();

HttpResponseMessage response = null;
this.client.Configure(cf =>
   {
      cf.AfterCall = http =>
         {
            response = http.Response;
         };
   });

var model = await client
   .AllowAnyHttpStatus()
   .Transactions
   .SendMoneyAsync(accountId, txn);

var httpCode = response.StatusCode;
bchavez commented 5 years ago

And another way...

var accountId = "aaa";
var txn = new CreateTransaction();

var model = await client
   .HoistResponse(out var responseGetter)
   .AllowAnyHttpStatus()
   .Transactions
   .SendMoneyAsync(accountId, txn);

var response = responseGetter();

var httpCode = response.StatusCode;

Using this extension:

public static class HoistExtensionsForCoinbaseClient
{
   public static CoinbaseClient HoistResponse(this CoinbaseClient client, out Func<HttpResponseMessage> responseGetter)
   {
      HttpResponseMessage msg = null;
      client.Configure(cf =>
         {
            cf.AfterCall = http =>
               {
                  msg = http.Response;
               };
         });

      responseGetter = () => msg;
      return client;
   }
}
granthoff1107 commented 5 years ago

Thanks the last one looks perfectSent from my Samsung Galaxy smartphone.