Node.jsでAPI経由で画像をアップロードする方法は?

これまで何度か質問されていますが、これまでの解決策は私のケースでは機能していません。

Node.js を使用して、API を通じて投稿に画像をアップロードしています。

投稿の作成は問題なくできますが、画像のアップロードができません。

画像(PNG ファイル)をバイナリ文字列に変換しています。

その後、ヘッダーに API 認証情報を付け、application/json リクエストを送信し、以下のようなペイロードを使用しています。

{
   type: "composer",
   synchronous: true,
   file: `${binary_string}`
}

API ドキュメントに従ってフィールド名を file にした場合も、フォーラムの別の投稿 で提案された files[] にした場合も試しました。

file を使用した場合は、422 エラーが発生し、以下のメッセージが表示されます。

undefined method `tempfile' for #<String:0x00007fdfeba2b1d8>

files[] を使用した場合は、「Unprocessable Entity」を含む 422 エラーが発生します。

ドキュメントでは application/json とされていますが、Web UI やこの投稿者が行ったように multipart/form-data も試しました。

form-data のポストは以下のように行いました。

 const form = new FormData();
 form.append("type", "composer");
 form.append("synchronous", "true");
 form.append("files[]", this.stringToBinary(file.data!), {
      contentType: file.mimetype,
 });

http.post("/uploads.json", form.getBuffer(), {
  headers: form.getHeaders(),
 }) // 認証情報は追加されます

この方法でも、file でも files[] でも、422 エラーが発生し、以下のエラーメッセージが表示されます。

undefined method `tempfile' for #<String:0x00007fdfeba2b1d8>

どなたかお手伝いできませんか?

これで動作するようになりました。以下のように実装しました:

import Axios from "axios";
import FormData from "form-data";
import fs from "fs";
const http = Axios.create({
  baseURL: "https://forum.zeebe.io",
  headers: {
    "Api-Key":
      "...",
    "Api-Username": "...",
    "Content-Type": "application/json",
    Accept: "application/json",
  },
});
http.interceptors.request.use((config) => {
  if (config.data instanceof FormData) {
    Object.assign(config.headers, config.data.getHeaders());
  }
  return config;
});

const filename = "/Users/sitapati/Desktop/process.png";
const file = fs.readFileSync(filename);
const form = new FormData();
form.append("files[]", file, {
  filename,
});

http
  .post("/uploads.json", form, {
    params: {
      type: "composer",
      synchronous: true,
    },
  })
  .then(({ data }) => {
    console.info("Discourse からのレスポンス", JSON.stringify(data, null, 2));
    return {
      url: data.url,
    };
  })
  .catch((e) => {
    console.error(
      "Discourse へのファイルアップロードエラー",
      JSON.stringify(e, null, 2)
    );
    throw e;
  });

リモート URL から取得したファイルでも動作します。その場合は以下のように取得する必要があります:

Axios.get(file.slackUrl, {
   responseType: "arraybuffer",
   headers: { Authorization: "Bearer " + this.slackToken },
})

ここで重要なのは responseType: "arraybuffer" です。