RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.82k stars 1.3k forks source link

Typescript generator doesn't properly encode arrays and objects for Form data. #3163

Open DDtMM opened 4 years ago

DDtMM commented 4 years ago

According to swagger.io:

Form fields can contain primitives values, arrays and objects. By default, arrays are serialized as array_name=value1&array_name=value2 and objects as prop1=value1&prop=value2

Arrays

Arrays only encode properly for Files. There is a specific branch of logic if file is detected and each item is appended one by one. This behavior should be the same for all array fields.

Objects

Because of the use of .toString(), all child objects are encoded as [object Object] when sent as form data.

Complications

This behavior for arrays and objects can be overriden by setting explode to false in the spec.

Suggestion

I'm not too familiar with LiquidTemplates, but in the following I normalize the field value as an array, and then call the encoding logic inside the forEach(). It seems like efficient output is preferred over a simpler template, but the normalizing as an array was done as an attempt to avoid repeating the encoding logic.

if ({{ parameter.VariableName }} !== null && {{ parameter.VariableName }} !== undefined) {
{%             else -%}
if ({{ parameter.VariableName }} === null || {{ parameter.VariableName }} === undefined) {
    throw new Error("The parameter '{{ parameter.VariableName }}' cannot be null.");
} else {
{%             endif -%}
    {% if parameter.IsArray -%}{{ parameter.VariableName }}{% else -%}[{{ parameter.VariableName }}]{% endif -%}.forEach(item => {
{%             if parameter.IsFile -%}
        content_.append("{{ parameter.Name }}", item);
{%             else -%}
        content_.append("{{ parameter.Name }}", JSON.stringify(item)); // this will call toJSON() on date, fix [object Object] for objects.
{%             endif -%}
    });
}
{%             endif -%}
Samuel-Therrien-Beslogic commented 1 month ago

I've been working around this issue by manually overriting in my main file. But this ain't pretty and other devs not aware of the issue get bitten when a new array is added:

import { Seeds, Species } from '@services/api.ts' // api.ts is generated by NSwag

// Monkeypatching to work around multipart/form-data issue with NSwag
Seeds.prototype.toString = function() {
  return JSON.stringify(this.toJSON())
}
Species.prototype.toString = function() {
  return JSON.stringify(this.toJSON())
}