Skip to content
This repository has been archived by the owner on Oct 25, 2022. It is now read-only.

client side uploads: bring your own S3 url #127

Open
joernroeder opened this issue Nov 4, 2021 · 3 comments
Open

client side uploads: bring your own S3 url #127

joernroeder opened this issue Nov 4, 2021 · 3 comments

Comments

@joernroeder
Copy link

Hey, Not really an issue, but more a suggestion this time.

I'm uploading files from the front end to my dato instance and don't expose any secrets to the client, by basically following https://community.datocms.com/t/uploading-images-from-forms-via-netlify-functions/640/3 with two api endpoints.

  1. POST /get-upload-url which accepts a file name and returns a signed S3 url
  2. PUT the file to S3 via the url returned from .1
    (repeat that for every file, collect the paths, ids along the way)
  3. POST /create to finalize the submission which accepts the model data including the collected ids to tie it all together, create the uploads and items in dato.

apart from performing some funky dance with the server 💃🕺(which is fine) I ended up copying the uploadToS3 function because it already has built in progress and cancellation. I would love to see a convenient import { uploadToS3 } from 'datocms-client' export which I can use an bring my own S3 signed url.

From looking at it, this looks like a good entry point https://github.com/datocms/js-datocms-client/blob/master/src/upload/adapters/browser.js#L50

@stefanoverna
Copy link
Member

That seems doable, sure. Would it be OK to simply export the uploadToS3 function? https://github.com/datocms/js-datocms-client/blob/master/src/upload/adapters/browser.js#L50 is just some code that glues the creation of upload request with the upload itself.

@stefanoverna
Copy link
Member

stefanoverna commented Nov 4, 2021

See ad8acad.

In browsers:

import { uploadToS3 } from 'datocms-client/lib/upload/adapters/browser';

On Node:

import { uploadToS3 } from 'datocms-client/lib/upload/adapters/node';

@joernroeder
Copy link
Author

joernroeder commented Nov 4, 2021

yeah, that's a good start and would remove duplication. I envisioned something which also takes care of the cancellation but I can also glue that together myself.

My Idea was something like below (untested, dummy code) but with a proper name :D

export const doIt = (uploadRequestPromise, file, { onProgress }) => {
  let isCancelled = false;
  let cancel = () => {
    isCancelled = true;
  };

  const promise = uploadRequestPromise
    .then(({ id, url }) => {
      if (isCancelled) {
        return Promise.reject(new Error('upload aborted'));
      }
      if (onProgress) {
        onProgress({
          type: 'uploadRequestComplete',
          payload: {
            id,
            url,
          },
        });
      }
      const { promise: uploadPromise, cancel: cancelUpload } = uploadToS3(
        file,
        url,
        {
          onProgress,
        },
      );
      cancel = cancelUpload;
      return uploadPromise.then(() => id);
    });

  return {
    promise,
    cancel: () => {
      cancel();
    },
  };
}


export default function browser(client, file, { onProgress, filename }) {
  const uploadRequestPromise = client.uploadRequest.create({ filename: filename || file.name })

  return doIt(uploadRequestPromise, file, { onProgress });
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants