openapiminimal-apis.net-9.0kiota

Issue with Kiota MultipartBody in TypeScript: "unsupported content type for multipart body"


I’m trying to send a multipart/form-data request to a minimal API using the Kiota-generated HTTP client.

Full scenario here.

When I try to call the post function generated by Kiota, I receive the following error: Error: unsupported content type for multipart body: object.

C# Endpoint:

app.MapPost("/handle-form", async (HttpRequest request) =>
{
    IFormCollection form = await request.ReadFormAsync();

    MyForm myForm = new()
    {
        Name = form["Name"]!,
        Comment = form["Comment"],
        MyFile = form.Files["MyFile"]!,
        Attachments = [.. form.Files.Where(x => Regex.IsMatch(x.Name, @"^Attachments\[\d+\]$", RegexOptions.IgnoreCase))]
    };

    return Results.Ok(myForm);
})
.Accepts<MyForm>("multipart/form-data")
.DisableAntiforgery();

Typescript:

Generated method by Kiota:

/**
* @param body The request body
* @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
* @returns {Promise<ArrayBuffer>}
*/
post(body: MultipartBody, requestConfiguration?: RequestConfiguration<object> | undefined) : Promise<ArrayBuffer | undefined>;

Use client:

const handleFormSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget); 
    const name = formData.get("name")?.toString() || "";
    const comment = formData.get("comment")?.toString() || "";
    const myFile = formData.get("myFile") as File;
    const attachments = Array.from(formData.getAll("attachments")) as File[];
  
    const multipartBody = new MultipartBody();

      multipartBody.addOrReplacePart("Name", "application/text-plain", name);
      multipartBody.addOrReplacePart("Comment", "application/text-plain", comment);
      multipartBody.addOrReplacePart("MyFile", "application/octet-stream", myFile);
      attachments.forEach((file, index) => {
        multipartBody.addOrReplacePart(`Attachments[${index}]`, "application/octet-stream", file);
      });

    await client.handleForm.post(multipartBody); // Error while sending post: Error: unsupported content type for multipart body: object
}

My second question is whether there is a way to generate a TypeScript interfaces in model directory from the OpenAPI schema, in order to ensure type safety and maintain type integrity between the C# class and the TypeScript type:

"schemas": {
  "MyForm": {
    "type": "object",
    "properties": {
      ...
      }
    }
  }
}

Any insights on this matter would be highly appreciated, thank you in advance.


Solution

  • Have you tried to call .arrayBuffer() or .stream() on the file parts before passing them to the multipart body?

    File is just the metadata about the file on storage, and a pointer to the content.

    But the multipart body expects the "content" of the file

    So in effect

    -multipartBody.addOrReplacePart("MyFile", "application/octet-stream", myFile);
    +multipartBody.addOrReplacePart("MyFile", "application/octet-stream", await myFile.bytes());
    

    As for the second question, the reason why kiota is not generating a model for the main request body is because multipart bodies require a lot more information than "regular" bodies. Like the part media type, file name, etc... The different serialization layers were not designed to accommodate passing that much information around. And even if it did, it wouldn't guarantee a great developer experience/quality of the API surface