Following the documentation of API Platform, we start with an API that accepts the multipart/form-data format.

curl -X POST "http://127.0.0.1:8001/api/media_objects" -H "accept: application/ld+json" -H "Content-Type: multipart/form-data" -F "file=@file.png;type=image/png"

We use Sapper (Node.js+Express) as an API gateway. First, we need to send a local file from Svelte to the Sapper server. Sapper then receives the file and calls external API.

Sending the file with Svelte

// components/File/Upload.svelte
<script>
  let files;
  let statusCode = "";

  async function handleSubmit() {
    if (files.length > 0) {
      const formData = new FormData();
      formData.append("file", files[0]);
      const response = await fetch("/gateway/media_objects", {
        method: "POST",
        body: formData
      });
      statusCode = response.status;
    }
  }
</script>

{statusCode}
<form on:submit|preventDefault={handleSubmit}>
  <label for="file">File</label>
  <input required id="file" type="file" bind:files />
  <input type="submit" value="Upload file" />
</form>

FormData automatically adds the correct format to the Sapper server. /gateway/media_objects is the Sapper route

Processing the file on NodeJs

This part is more tricky. Normally I used the body-parser package to parse the request data in a more usable format:

// server.js
import bodyParser from 'body-parser'
...
app.use(
  bodyParser.urlencoded({
    extended: true
  }),
  bodyParser.json(),
)

Unfortunatly, body-parser does not support multiparts bodies:

This does not handle multipart bodies, due to their complex and typically large nature.

So, we need to use some other package. I have chosen express-formiddable since we are already running Express with Sapper.

//server.js
const formidableMiddleware = require('express-formidable');
...
app.use(formidableMiddleware());

Sapper Route, calling the PHP API

We can now create the Sapper route. The file will be located under req.files.file and should be fully uploaded. The file should be located in the req.files.file.path folder.

To be able to send files with NodeJs we need to add the form-data package. As it is not in NodeJs by default. The node-fetch package is needed as well to call the API.

We need to convert the uploaded file to a readStream in the formData.

// routes/gateway/media_objects.js
const fetch = require('node-fetch');
var fs = require('fs');
var FormData = require('form-data');

export async function post(req, res, next) {
  // External API information.
  const { API_SERVICE, API_KEY } = process.env;
  let formData = new FormData();
  formData.append('file', fs.createReadStream(req.files.file.path), req.files.file.name);
  const response = await fetch(API_SERVICE + '/api/media_objects',
    {
      method: 'POST',
      headers: {
        'API-KEY': API_KEY
      },
      body: formData,
    });
  res.sendStatus(response.status);
}

Discussion

And that it is! You should be able to send files using Sapper / Node.js to your external API.

These FormData requests could be an alternative to JSON for other types of fields as well. At least it is good to know that FormData is sometimes used as an alternative way to send data and that it works well for files.

Did you like this article please consider sharing it with your peers. If you want to support this blog you can buy me a coffee. Thanks for all the people that read the blog and special thanks for those who donated!


0 Comments

Leave a Reply

Your email address will not be published.