Symfony : uploading file, working from Postman, not from Javascript nor cURL

Symfony : uploading file, working from Postman, not from Javascript nor cURL

I’m trying to make a request from a Javascript file to an upload file route made with Symfony and API Platform.

REQUESTS :

  1. With Postman, using the file input under form-data and using the GUI, the upload works (201 response).

  2. When I try the generated cURL into my terminal :

curl --location --request POST 'http://localhost:8000/api/media_objects' 
--header 'Content-Type: application/json' 
--header 'Authorization: Bearer long_bearer_token' 
--form '[email protected]/Users/tomsihap/Desktop/file.png'
  1. I’ve also tried with :
curl --location --request POST 'http://localhost:8000/api/media_objects' 
--header 'Content-Type: application/json' 
--header 'Authorization: Bearer long_bearer_token' 
-F '[email protected]/Users/tomsihap/Desktop/file.png'
  1. Or even the Javascript generated code (the one I’d like to use) :
var data = new FormData();
data.append("file", BlobObject, "file.png");

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function() {
  if(this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "http://localhost:8000/api/media_objects");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer long_bearer_token");

xhr.send(data);
  1. Also, my original code from my Angular project :
private convertBase64ToBlob(Base64Image: any) {
    // Split into two parts
    const parts = Base64Image.split(';base64,');

    // Hold the content type
    const imageType = parts[0].split(':')[1];

    // Decode Base64 string
    const decodedData = window.atob(parts[1]);

    // Create UNIT8ARRAY of size same as row data length
    const uInt8Array = new Uint8Array(decodedData.length);

    // Insert all character code into uInt8Array
    for (let i = 0; i < decodedData.length; ++i) {
      uInt8Array[i] = decodedData.charCodeAt(i);
    }

    // Return BLOB image after conversion
    return new Blob([uInt8Array], { type: imageType });
  }

const frmData = new FormData();
    frmData.append('file', this.convertBase64ToBlob(data));
    return this.http.post(`${this.baseUrl}/api/media_objects`, frmData, this.getTokenWithFormData()).pipe(
      catchError((err) => {
        this.handleError(err);
        return throwError(err);
      })
    );
  1. And the exact same one without converting to Blob:
const frmData = new FormData();
    frmData.append('file', data);
    return this.http.post(`${this.baseUrl}/api/media_objects`, frmData, this.getTokenWithFormData()).pipe(
      catchError((err) => {
        this.handleError(err);
        return throwError(err);
      })
    );

It doesn’t work.

RESPONSE :

When “it doesn’t work”, 400 response is :

{ 
    "@context": "/api/contexts/Error",
    "@type": "hydra:Error",
    "hydra:title": "An error occurred",
    "hydra:description": ""file" is required",

PHP CODE :

And here is where the error occurs (this file is being called when going to /api/media_objects to handle the file) :

final class CreateMediaObjectAction
{
    public function __invoke(Request $request): MediaObject
    {
        $uploadedFile = $request->files->get('file');
        if (!$uploadedFile) {
            throw new BadRequestHttpException('"file" is required');
        }

        $mediaObject = new MediaObject();
        $mediaObject->file = $uploadedFile;

        return $mediaObject;
    }
}

And here is how the MediaObject entity is defined with API Platform :

/**
 * @ORMHasLifecycleCallbacks()
 * @ORMEntity
 * @ApiResource(
 *     iri="http://schema.org/MediaObject",
 *     normalizationContext={
 *         "groups"={"media_object_read"}
 *     },
 *     collectionOperations={
 *         "post"={
 *             "controller"=CreateMediaObjectAction::class,
 *             "deserialize"=false,
 *             "access_control"="is_granted('ROLE_USER')",
 *             "validation_groups"={"Default", "media_object_create"},
 *             "openapi_context"={
 *                 "requestBody"={
 *                     "content"={
 *                         "multipart/form-data"={
 *                             "schema"={
 *                                 "type"="object",
 *                                 "properties"={
 *                                     "file"={
 *                                         "type"="string",
 *                                         "format"="binary"
 *                                     }
 *                                 }
 *                             }
 *                         }
 *                     }
 *                 }
 *             }
 *         },
 *         "get"
 *     },
 *     itemOperations={
 *         "get"
 *     }
 * )
 * @VichUploadable
 */
class MediaObject {

// ...

/**
     * @var File|null
     *
     * @AssertNotNull()
     * @VichUploadableField(mapping="media_object", fileNameProperty="filePath")
     */
    public $file;

MY QUESTION :

How to make this file upload work from Javascript ?

Source: Symfony Questions

Leave a Reply

Your email address will not be published. Required fields are marked *