XeroAPI/xero-node

Can't upload files from AWS S3

arampetrosyann opened this issue · 10 comments

let localVarRequestOptions: localVarRequest.Options = {

I'm getting an error when trying to upload a file. (Files API)

The error is - { type: 'Validation', title: 'Validation failure', detail: 'No file is was attached' }

Request body is missing in request options.

Hi @arampetrosyann I'm unable to replicate your error using our sample app.

Code snippet:

const filename = "xero-dev.png";
const pathToUpload = path.resolve(__dirname, "../public/images/xero-dev.png");
const readStream = fs.createReadStream(pathToUpload);
const contentType = mime.lookup(filename);

const uploadFile = await xero.filesApi.uploadFile(req.session.activeTenant.tenantId, readStream, filename, contentType);

Response body:

{ "name": "xero-dev.png", "mimeType": "image/png", "size": 34843, "createdDateUtc": "2022-11-07T21:53:13.8370000", "updatedDateUtc": "2022-11-07T21:53:13.8370000", "user": { "id": "96536500-45b9-4170-b4ad-40c180fb9f48", "name": "rett.behrens@xero.com", "firstName": "Rett", "lastName": "Behrens", "fullName": "Rett Behrens" }, "id": "a38238cf-d108-416b-8206-89655c7a8b2b", "folderId": "f8405741-5cbb-405f-9343-2cc221004843" }

File in Xero UI:
Screen Shot 2022-11-07 at 15 01 48

Can you please provide more information?

  • What version of Xero-Node SDK are you using?
  • Can you include a code snippet?

Hi @RettBehrens

Code:

    const fileStream = s3
      .getObject({
        Bucket: file.bucket,
        Key: file.externalKey,
      })
      .createReadStream()

    const [fileName, mimeType] = this.constructor.processFileName(fileExp.name)

    const res = await this.filesApi.uploadFile(
      this.tenantId,
      fileStream,
      fileName,
      fileName,
      mimeType
    ) 

I'm using AWS S3.

Version of SDK - 4.21.0

Is there any additional indication of where this error is originating?
{ type: 'Validation', title: 'Validation failure', detail: 'No file is was attached' }

When testing in the sample app, the SDK error if no body present is Error: Required parameter body was null or undefined when calling uploadFile.

Can you provide your app Client ID so I can check the logs on our side?

@arampetrosyann checking in to see if you've resolved the issue on your end or if this remains ongoing?

@RettBehrens no I couldn't resolve that. The error comes from response.

Client ID - A2F4E2DB397C4107B2671C1FB4B14F27
Correlation ID - bcfa76c7-5774-4daf-8536-458d755e9e3d

Your request resulting in 400:

----------------------------998237666144744215888171
Content-Disposition: form-data; name="name"

bairds-sandpiper-gff0f83b00_1280.jpg
----------------------------998237666144744215888171
Content-Disposition: form-data; name="filename"

bairds-sandpiper-gff0f83b00_1280.jpg
----------------------------998237666144744215888171
Content-Disposition: form-data; name="mimeType"

image/jpeg
----------------------------998237666144744215888171
Content-Disposition: form-data; name="bairds-sandpiper-gff0f83b00_1280.jpg"
Content-Type: application/octet-stream

My request resulting in 201:

----------------------------459349396614277166041519
Content-Disposition: form-data; name="name"

xero-dev.png
----------------------------459349396614277166041519
Content-Disposition: form-data; name="filename"

xero-dev.png
----------------------------459349396614277166041519
Content-Disposition: form-data; name="mimeType"

image/png
----------------------------459349396614277166041519
Content-Disposition: form-data; name="xero-dev.png"; filename="xero-dev.png"
Content-Type: image/png

I see that your Content-Type does not match your mimeType, where mine does. Can you try overriding the value with the correct type and send the request again?

Allowed file types:

BMP NUMBERS RTF
CSV ODF RTF/TEXT
DOC ODS TIF
DOCX ODT TIFF
EML PAGES TXT
GIF PDF XLS
JPEG PNG XLSX
JPG PPT ZIP
KEYNOTE PPTX 7Z
MSG RAR  
    const [fileName, mimeType] = this.constructor.processFileName(fileExp.name)

    const res = await this.filesApi.uploadFile(
      this.tenantId,
      fileStream,
      fileName,
      fileName,
      mimeType,
      { headers: { 'Content-Type': mimeType } }
    ) 

Result is the same.

Correlation ID - e02361e0-b055-47ea-ac38-166f50b132e2

The request header content type is correct, however, the request body is still showing application/octet-stream. Reading the docs it seems S3 will default to application/octet-stream if you don't specify content type when uploading. It seems you can also specify content type when calling getObject Can you try this?

const fileStream = s3
      .getObject({
        Bucket: file.bucket,
        Key: file.externalKey,
        ResponseContentType: 'image/jpeg',
      })
      .createReadStream()

If the above works, can you specify content type when uploading to S3?

That was inefficient.

Correlation ID - 61c63e0d-f8ce-4a15-8595-a4b91f107549

I always recieve the same error message.

Can I send a file with base64 format?

Hi @arampetrosyann

From the dev team:

I tried uploading a file with Content-Type set to application/octet-stream as seen in the attached screen capture. The API seems to resolve to the actual content-type of the file attached (if the file exists).. The only instance I see this 400 error is if there is no file attached with the request. Do you know if the user has validated that they've retrieved the file from S3 successfully?

files-api-uploading-a-file

Additionally:

The other difference in the two requests you posted here, is that yours has a name and a filename whereas his request only has name could that be messing with it?

Based on the dev team feedback, I have a couple questions:

  • Can you confirm you're successfully retrieving the file from S3?
  • Can you console.log the output for const [fileName, mimeType] = this.constructor.processFileName(fileExp.name)?