5

I am attempting to post some data that includes a string array to an endpoint but receiving an error "Invalid array"

Doing this:

   .PostUrlEncodedAsync(new
     {
        amount = 1000,
        allowed_source_types = new[] { "card_present" },
        capture_method = "manual",
        currency = "usd"
     });

Results in this being posted:

amount=1000&allowed_source_types=card_present&capture_method=manual&currency=usd

The API vendor complains that the array that I posted is invalid. When I do this:

    .PostUrlEncodedAsync(
             "amount=1000&allowed_source_types[]=card_present&capture_method=manual&currency=usd"
    );

Results in this being posted:

amount=1000&allowed_source_types[]=card_present&capture_method=manual&currency=usd

The API vendor is happy and I get the expected results.

Question: Is this a bug and should the allowed_source_types parameter have included the [ ] as initially detailed here?

Stephen McDowell
  • 839
  • 9
  • 21
  • 1
    In URL parlance, using `allowed_source_types[]=card_present` sets the value of the parameter named `allowed_source_types[]` to the single value `card_present` -- which is not the same as setting a parameter named `allowed_source_types`. An API can certainly use parameter names with `[]` in them (if properly encoded when sent over to the server) but it's not standard. It would not be correct for Flurl to add the `[]` without being asked to. The tricky bit of course is that you can't specify a property with `[]` in the name in C#, so an alternate mechanism is needed for that. – Jeroen Mostert Feb 04 '19 at 14:57
  • 1
    It's also worth checking if the API accepts the "standard" way of passing multi-valued parameters (`a=val1&a=val2&a=val3`) or if it uses something else there too (`a[]=val1,val2,val3`). The latter is also not something a generic library should do without being asked to. (Having said that, the standards don't actually say anything about multi-valued parameters, but the first way is the one browsers have used since the days of yore, hence "standard". APIs may well have different ideas.) – Jeroen Mostert Feb 04 '19 at 15:02
  • @JeroenMostert Everything in your comments is exactly right, and what you describe as most "standard" is exactly what Flurl does, so I'd invite you to put that in an answer. `PostUrlEncodedAsync` gives special treatment to dictionaries, which is the best way I can think of to get the `[]` added. – Todd Menier Feb 04 '19 at 15:19
  • @ToddMenier: I have no experience whatsoever using Flurl, so there's probably a better answer possible to someone who does. Specifically, the "proper" way to call this API in a Flurl-accepted way would be good (posting a literal query string you made yourself is always possible, of course, but that's the least attractive way). – Jeroen Mostert Feb 04 '19 at 15:21
  • @JeroenMostert - Thanks for the details. Learned something for sure. Had tried passing the equivalent of a=val1&a=val2&a=val3 and the API gave an 'invalid array' error. – Stephen McDowell Feb 05 '19 at 12:55

1 Answers1

6

It's not a bug. As mentioned in the comments, there's no standard for URL-encoding a collection, but doing it like this:

x[]=1,2,3

is a lot less common than doing it like this:

x=1&x=2&x=3

The latter is how Flurl has implemented it.

The trouble with doing it the way the API requires is that [] are not valid in a C# identifier, so the typical object notation won't work. But Flurl gives special treatment to Dictionary objects, so your best bet is to do it like this:

.PostUrlEncodedAsync(new Dictionary<string, object>
{
    ["amount"] = 1000,
    ["allowed_source_types[]"] = "card_present", // or string.Join(",", allowedSourceTypes)
    ["capture_method"] = "manual",
    ["currency"] = "usd"
 });
Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • 1
    Thanks for providing the details. Passing the dictionary worked as expected. And thank you for giving us Flurl. You've made the C# world a better place! – Stephen McDowell Feb 05 '19 at 13:02