confact / stripe.cr

Stripe API Wrapper for crystal

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

List methods with parameters are broken

wezm opened this issue · comments

I think #40 broke list methods. The code generated prior to this change looked like this (for Price in this case):

builder.add("active", active) unless active.nil?
builder.add("product", product) unless product.nil?
⋮
builder.add("ending_before", ending_before) unless ending_before.nil?

after the changes in #40 the generated code looks like this:

def self.list(active : Bool | ::Nil = nil, product : String | ::Nil = nil, currency : String | ::Nil = nil, type : String | ::Nil = nil, lookup_keys : Array(String) | ::Nil = nil, recurring : Hash(String, String | Int32 | Nil) | ::Nil = nil, limit : Int32 | ::Nil = nil, created : Hash(String, Int32) | ::Nil = nil, starting_after : String | ::Nil = nil, ending_before : String | ::Nil = nil, expand : Array(String) | ::Nil = nil) : List(Stripe::Price)
  io = IO::Memory.new
  builder = ParamsBuilder.new(io)

  builder.add(active, active) unless active.nil?
  builder.add(product, product) unless product.nil?
  ⋮
  builder.add(ending_before, ending_before) unless ending_before.nil?

  response = Stripe.client.get("/v1/#{"price"}s", form: io.to_s)

  if response.status_code == 200
    List(Stripe::Price).from_json(response.body)
  else
    raise Error.from_json(response.body, "error")
  end
end

Note that the keys are no longer quoted. This results in parameters like this being generated:

"%5B%22price_1MJ8JLGRhOlPd2IWrLbjKJgs%22%5D%5B0%5D=price_1MJ8JLGRhOlPd2IWrLbjKJgs&%5B%22data.product%22%5D%5B0%5D=data.product"

which URL decoded is:

["price_1MJ8JLGRhOlPd2IWrLbjKJgs"][0]=price_1MJ8JLGRhOlPd2IWrLbjKJgs&["data.product"][0]=data.product

note how the value is being used as the key and value.

The following test added to price_spec.cr illustrates the problem:

  it "listing prices with params" do
    WebMock.stub(:get, "https://api.stripe.com/v1/prices")
      .with(body: "currency=AUD")
      .to_return(status: 200, body: File.read("spec/support/list_prices.json"), headers: {"Content-Type" => "application/json"})

    prices = Stripe::Price.list(currency: "AUD")
    prices.first.id.should eq("price_1IqjDxJN5FrkuvKhKExUK1B2")
  end

With resulting error:

       Real HTTP connections are disabled. Unregistered request: GET https://api.stripe.com/v1/prices with body "AUD=AUD" with headers {"Content-Length" => "7", "Content-Type" => "application/x-www-form-urlencoded", "Host" => "api.stripe.com", "Authorization" => "Bearer test"}

Note that the body has the value twice.

The solution appears to be a call to stringify in the add_list_method macro, which makes the above test pass:

  {% for x in arguments.map &.var.id %}
    builder.add({{x.stringify}}, {{x.id}}) unless {{x.id}}.nil?
  {% end %}

Thanks @wezm, added test and verified it was a bug. Fixed it in #58.