Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling WalletApi.walletBoxesCollect throws an exception #183

Open
jaysee260 opened this issue Jul 16, 2022 · 1 comment
Open

Calling WalletApi.walletBoxesCollect throws an exception #183

jaysee260 opened this issue Jul 16, 2022 · 1 comment

Comments

@jaysee260
Copy link

I am trying to use the new WalletApi to get some boxes from my wallet.

I created the wallet service like this

// conf is of type ErgoToolConfig
val apiClient = new ApiClient(conf.getNode.getNodeApi.getApiUrl, "ApiKeyAuth", conf.getNode.getNodeApi.getApiKey)
val walletService = apiClient.createService(classOf[WalletApi])

Then I'm using it like this to get some amount of ERG from my wallet

val getWalletBoxesRequest = new BoxesRequestHolder().targetBalance(Parameters.OneErg)
val response = walletService.walletBoxesCollect(getWalletBoxesRequest).execute()

But that call throws the following error:

Exception in thread "main" java.lang.IllegalArgumentException: Non-body HTTP method cannot contain @Body.

After a little digging, I found that WalletApi.walletBoxesCollect queries /wallet/boxes/collect in the node's API, which is a POST endpoint.
image

However, I noticed that the appkit method that queries that endpoint has a @GET annotation for it
image

It seemed like the fix was as simple as changing the annotation from @GET to @POST, so I tried it locally. For simplicity's sake, I created a Java interface in my codebase,

public interface NewWalletApi {
    @Headers({
            "Content-Type:application/json"
    })
    @POST("wallet/boxes/collect")
    Call<List<WalletBox>> walletBoxesCollect(
            @retrofit2.http.Body BoxesRequestHolder body
    );
}

updated the wallet service creation to use the interface,

val walletService = apiClient.createService(classOf[NewWalletApi])

and tried executing a request again.

val getWalletBoxesRequest = new BoxesRequestHolder().targetBalance(Parameters.OneErg)
val response = walletService.walletBoxesCollect(getWalletBoxesRequest).execute()

This time, I just got a Bad Request back from the node, no further details.

So I went to the node's Swagger page to inspect that endpoint further (POST /wallet/boxes/collect), and soon learned some things about the expected request body.

image

  1. targetAssets is required and cannot be null.
  2. In the Swagger example, targetAssets is shown as a List of Lists (the BoxesRequestHolder Java model reflects this).
  3. Sending a request, via the Swagger page, following this suggested structure results in a 400 - Bad Request.

I tried out a few combinations

// empty list
{
    "targetAssets": []
    ...
}

// empty list with empty list
{
    "targetAssets": [[]]
    ...
}

// list of lists with "dummy" values
{
    "targetAssets": [["", 0]]
    ...
}

None worked. Until finally I tried this, and it worked!

{
    // empty object/map
    "targetAssets": {}
    ...
}

image

So, it looks like

  1. targetAssets cannot be null but it can be empty.
  2. Despite the Swagger example, targetAssets needs to be an object/map (where each key/value pair represent asset_id/amount), NOT a list of lists (array of arrays).

So, I tried updating the targetAssets property in the BoxesRequestHolder model to a HashMap<String, Long>, executed another request from my code using appkit, but then I got this error:

Note: to facilitate and speed up local testing of this, I created a new model NewBoxesRequestHolder, updated targetAssets as needed, and used it to build a request body instead of BoxesRequestHolder

Click to expand
public class NewBoxesRequestHolder {
    @SerializedName("targetAssets")
    private java.util.HashMap<String, Long> targetAssets = new HashMap<>();

    @SerializedName("targetBalance")
    private Long targetBalance = null;

    public NewBoxesRequestHolder targetAssets(java.util.HashMap<String, Long> targetAssets) {
        this.targetAssets = targetAssets;
        return this;
    }

    public NewBoxesRequestHolder targetBalance(Long targetBalance) {
        this.targetBalance = targetBalance;
        return this;
    }

    public java.util.HashMap<String, Long> getTargetAssets() {
        return targetAssets;
    }

    public void setTargetAssets(java.util.HashMap<String, Long> targetAssets) {
        this.targetAssets = targetAssets;
    }

    public Long getTargetBalance() {
        return targetBalance;
    }

    public void setTargetBalance(Long targetBalance) {
        this.targetBalance = targetBalance;
    }
}

Exception in thread "main" java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $ at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:39) at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27) at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:225) at retrofit2.OkHttpCall.execute(OkHttpCall.java:188)

While I've figrued out how to send a valid request to POST /wallet/boxes/collect via the node's Swagger page, I have not yet managed to get it to work via appkit.

I'm still into it but this is as far as I've made it. If anyone has any useful insights into how to potentially resolve this issue, they'd be greatly appreciated!

@jaysee260
Copy link
Author

Found the source of the issue. The fix will require a small change in the node's OpenAPI YAML spec, and a couple of changes in app-kit.

Leaving this comment:

  • to mention I've found a solution
  • as a reminder to come back and leave more details.

@ergoplatform ergoplatform deleted a comment Sep 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant