Comment téléverser des images via l'API avec Node.js ?

Cela a été demandé à plusieurs reprises, mais aucune des solutions proposées jusqu’à présent ne fonctionne pour moi.

J’utilise Node.js pour télécharger des images pour un article via l’API.

Je peux créer des articles sans problème, mais les images ne se téléchargent pas.

Je convertis l’image (un fichier PNG) en une chaîne binaire.

Ensuite, j’envoie une requête application/json avec les identifiants de l’API dans les en-têtes et un corps comme celui-ci :

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

J’ai essayé d’utiliser file comme nom de champ pour le fichier, comme le mentionne la documentation de l’API, ainsi que files[], comme suggéré dans un autre post sur le Forum.

En utilisant file, je reçois une erreur 422 avec :

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

En utilisant files[], je reçois une erreur 422 avec le message « Unprocessable Entity ».

Outre application/json comme indiqué dans la documentation, j’ai également essayé multipart/form-data, comme le fait l’interface web et comme l’a fait cet utilisateur.

Pour la requête en form-data, je l’ai fait comme ceci :

 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(),
 }) // les identifiants sont ajoutés

Avec cette méthode, que ce soit avec file ou files[], je reçois une erreur 422 avec le message :

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

Quelqu’un peut-il m’aider ?

J’ai réussi à faire fonctionner cela de cette manière :

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("Réponse de Discourse", JSON.stringify(data, null, 2));
    return {
      url: data.url,
    };
  })
  .catch((e) => {
    console.error(
      "Erreur lors du téléchargement du fichier vers Discourse",
      JSON.stringify(e, null, 2)
    );
    throw e;
  });

Cela fonctionne également avec un fichier récupéré depuis une URL distante, ce qui doit être fait de cette manière :

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

L’élément clé ici est : responseType: "arraybuffer".