NextJs, Google Cloud Storage, problem with upload/download an object in memory

Viewed 1864

I am new to using blobs and GCS and could do with some help and a sanity check on what I have written.

I am building a web app using Nextjs.
The user can drag an image on to the page.
I want to store the image in GCS.
As the image will only be viewable in the web app, I believe that I want to turn the image into a blob and store that.
To subsequently display the image I just download the blob from GCS when required.

My questions is in two parts:

  • A. How to upload a blob to GCS?
  • B. How to download a blob from GCS?

My efforts so far are close but something is going wrong somewhere:

  • The blob seems to be uploaded and downloaded ok but I cant get the blob to display after retrieval from GCS.
  • I am seeing discrepancies in blob size before uploading (size:239536) and after downloading (size: 439114).
  • The downloaded blob fails to display after conversion with URL.createObjectURL().

Below is what I have tried so far.

A. How to upload a blob to GCS?

Client-side
First I get the image data from a component and convert to a blob:

// getImageScaledToCanvas(): This returns a HTMLCanvasElement, it can be made into a data URL or a blob
const imgData = ref.current.getImageScaledToCanvas()  
imgData.toBlob((blob) => saveImageDataToBucket(blob))

Logging the blob shows:
Blob { size: 239536, type: "image/png" }

Then I execute a fetch to send the blob to my API:

await fetch(/api/saveImageToBucket,  
{
    method: 'POST',  
    body: blob  
})
.then(response => response.text())
.then(data => console.log('SAVE IMAGE TO BUCKET, fileName=', data))
.catch( err => console.log(err)
)
}

Server-side
The API executes successfully:

try {
       const bucket = googleCloudStorage.bucket(bucketName)
       const file = bucket.file('myImgBlob)
       const stream = file.createWriteStream({resumable:false, gzip:true})
       stream.write(req.body)
       stream.end()
       res.status(200).send('myImgBlob')
    }
    catch (e) {
        res.status(500).json({error: e})
}

Note: Nextjs uses API routes which provide built in middlewares which parse the incoming request (req).
req.body is an object containing the body parsed by content-type.

The file is created on GCS (191.39 KB) and I send the fileName back to the client.

B. How to download a blob from GCS?

Client-side
Execute a fetch to get the image blob from GCS:

await fetch(`/api/getImageFromBucket`,
{
    method: 'GET',
})
.then(response => response.blob())
.then(blob => {
    const imgBlob = new Blob([blob], {type: 'image/png'})
    setTestImage(imgBlob)
})
.catch( err => console.log(err)
)

Logging the blob shows: Blob { size: 439114, type: "image/png" }

Then I just want to render the blob out to a tag to check that all is ok.

const imgUrl=URL.createObjectURL(testImage)
<img src={imgUrl} />

However the image fails to display on the page.

Server-side
The API executes successfully:

try {
    const bucket = googleCloudStorage.bucket(bucketName)
    const file = bucket.file('myImgBlob')

    // Download a file into memory.
    //
    await file.download()
          .then((data) => {
              const contents = data[0]
              res.status(200).send(contents)
          })
    }
    catch (e) {
        res.status(500).json({error: e})
}
0 Answers
Related