Wie man Bilder über API mit Node.js hochlädt

Dies wurde bereits mehrfach gefragt, aber keine der bisherigen Lösungen hat bei mir funktioniert.

Ich verwende Node.js, um über die API Bilder für einen Beitrag hochzuladen.

Das Erstellen von Beiträgen funktioniert problemlos, aber Bilder werden nicht hochgeladen.

Ich konvertiere das Bild (eine PNG-Datei) in einen Binärstring.

Anschließend sende ich eine application/json-Anfrage mit den API-Anmeldedaten in den Headern und einem Payload wie diesem:

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

Ich habe sowohl file als Feldnamen für die Datei verwendet, wie in der API-Dokumentation angegeben, als auch files[], wie in einem anderen Beitrag im Forum vorgeschlagen.

Bei Verwendung von file erhalte ich einen 422-Fehler mit:

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

Bei Verwendung von files[] erhalte ich ebenfalls einen 422-Fehler mit der Meldung „Unprocessable Entity“.

Neben application/json, wie in der Dokumentation angegeben, habe ich es auch als multipart/form-data versucht, wie es die Web-Oberfläche und dieser Poster tun.

Für den Form-Daten-Post habe ich es so gemacht:

 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(),
 }) // creds get added

Bei diesem Ansatz erhalte ich sowohl mit file als auch mit files[] einen 422-Fehler mit der Meldung:

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

Kann mir jemand helfen?

Ich habe es so zum Laufen gebracht:

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("Antwort von Discourse", JSON.stringify(data, null, 2));
    return {
      url: data.url,
    };
  })
  .catch((e) => {
    console.error(
      "Fehler beim Hochladen der Datei nach Discourse",
      JSON.stringify(e, null, 2)
    );
    throw e;
  });

Es funktioniert auch mit einer Datei, die von einer Remote-URL abgerufen wird. Diese muss wie folgt abgerufen werden:

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

Der Schlüssel hier ist: responseType: "arraybuffer".