Come caricare immagini tramite API con Node.js?

Questa domanda è stata posta varie volte, ma nessuna delle soluzioni finora proposte funziona per me.

Sto usando Node.js per caricare immagini per un post tramite l’API.

Posso creare post senza problemi, ma le immagini non vengono caricate.

Convertò l’immagine (un file PNG) in una stringa binaria.

Poi invio una richiesta application/json con le credenziali dell’API nell’intestazione e un payload come questo:

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

Ho provato sia file come nome del campo per il file, come indicano le documentazioni API, sia files[], come suggerito in un altro post sul Forum.

Usando file, ottengo un errore 422 con:

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

Usando files[], ottengo un errore 422 con “Unprocessable Entity”.

Oltre a application/json, come indicato nelle documentazioni, ho anche provato multipart/form-data, come fa l’interfaccia web e come ha fatto questo utente.

Per il post con form-data, l’ho fatto così:

 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(),
 }) // le credenziali vengono aggiunte

Con questo metodo, sia con file che con files[], ottengo un errore 422 con il messaggio:

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

Qualcuno può aiutarmi?

Ho fatto funzionare questo, in questo modo:

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("Risposta da Discourse", JSON.stringify(data, null, 2));
    return {
      url: data.url,
    };
  })
  .catch((e) => {
    console.error(
      "Errore durante il caricamento del file su Discourse",
      JSON.stringify(e, null, 2)
    );
    throw e;
  });

Funziona anche con un file recuperato da un URL remoto, che deve essere ottenuto in questo modo:

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

La chiave qui è: responseType: "arraybuffer".

7 Mi Piace