Error posting to /client-tokens from drop-in component

I’m testing using the drop-in components. Per the instructions, I created an endpoint /generate_client_token that proxies requests to dwolla’s /client-tokens endpoint. I then dropped the <dwolla-business-vcr /> tag on the page. As expected it made a POST to /generate_client_token with body {"action":"customer.create"} which was proxied to dwolla’s endpoint and received a successful response. The page then showed me the bvcr creation tool and I went through the wizard. At the end of the wizard the component attempted to make another request, this time with body {"action":"customer.read","links":{"customer":{"href":"https://api-sandbox.dwolla.com/customers/1e4ecca9-5185-46e4-8d18-0a116aff6969"}}} and the response from the API was not successful. Instead, the response received from the API was { "code": "BadRequest", "message": "The request body contains bad syntax or is incomplete." }.

What could be going wrong here? It seems to me like Dwolla’s own component should never generate a request that the API rejects…

Hi @noah – would you be able to share any/all relevant code from you project for generating client-tokens and your configuration object? Also, which version of dwolla-web.js are you using?

I am seeing this same request body in our logs. I did notice the "links" object which should be "_links". That’s what seems to be causing the BadRequest error. I’m not able to recreate in Sandbox using dwolla-web.js v2.1.9, which makes me think it might be a version issue :thinking: .

Happy to share code, it’s very straightforward…

The dwolla-web script tag’s src is set to //cdn.dwolla.com/v2.1.9/dwolla-web.js so unless there’s a very funny filing system I must be using v2.1.9.

After that script tag i have another script that runs dwolla.configure:

dwolla.configure({
  environment: "sandbox",
  success: (res: any) => Promise.resolve(),
  error: (err: any) => Promise.resolve(),
  token: (req: any) => api.GenerateClientToken(req)
});

The api.GenerateClientToken function is defined in Typescript as:

public async GenerateClientToken (body: Record<string, any>) {
  const url = `${API_BASE_URI}/dwolla/generate_client_token`;
  const headers = {
    Accept: "application/json",
    "Content-Type": "application/json",
    "X-Requested-With": "Dwolla-Drop-Ins-Library",
  };
  const response = await fetch(url, { method: 'POST', body: JSON.stringify(body), headers });
  const json = await response.json();
  return json;
}

Which obviously just forwards the body to my API. The api endpoint couldn’t get much simpler (in Python with self._app_token being set to dwollav2.Client(...).Auth.client() ):

def generate_client_token(self, body):
  response = self._app_token.post('/client-tokens', body)
  return response.body

That’s about it… It’s super simple which is why I’m so flummoxed…

Thanks for sharing your code, @noah! It looks like the body just needs to be reconstructed before being sent to the API as follows:

public async GenerateClientToken (body: Record<string, any>) {
  const url = `${API_BASE_URI}/dwolla/generate_client_token`;
  const headers = {
    Accept: "application/json",
    "Content-Type": "application/json",
    "X-Requested-With": "Dwolla-Drop-Ins-Library",
  };
  const req = {
    action: body.action,
  };
  if (body.links) {
    req._links = body.links;
  }
  const response = await fetch(url, { method: 'POST', body: JSON.stringify(req), headers });
  const json = await response.json();
  return json;
}

Please try the above and let me know if you if that works or if you run into any errors!

I could do that. But it seems very odd to me that the Dwolla drop-in component wouldn’t generate the proper request for the Dwolla api endpoint…

This is definitely a bug with the request body that Dwolla is providing when using drop-ins (specifically I’m seeing the exact same bug that Noah is pointing out when using dwolla-business-vcr in sandbox). There shouldn’t be a need to reformat a request body that is originating from Dwolla itself.

Thanks @Ben_Davidson and @noah!

Agreed! We have logged this as a feedback item and will be working on an update so that the library returns and object that does not need to be reformatted before passing on to the API.