Use custom meta data set in pre-create hook in uppy

Hi :slight_smile:

Using tusd (docker container) with https hooks to register uploads with my main application, so far, the hook integration went well.

I am now trying to return the register details to the client so it can continue working with this.

Imagine the following flow:

  1. User uploads file
  2. pre-create hook sets custom id tenantId/uuid
  3. post-create hook registers the upload within a postgres files table
  4. the client recieves the uuid of the file
  5. with the uuid of the registered file, the client can link the file with other resources e.g. linking the file as profile_picture_id in user_profiles.

I am currently stuck at step 4 - how do I return that info to the uppy client?

I tried modifying the MetaData in the pre-create hook or changing the HTTPResponse, but nothing appears to be part of the files json that I can access with uppy.

Any pointers, especially on other resources showing best practices in this, are very welcome.

Thanks!

Hello,

in the pre-create hook you can modify the response header and/or body using by setting the HTTPResponse property as explained in Customization via hooks | tusd documentation. On the client’s side, you can use tus-js-client’s onBeforeResponse callback to inspect the HTTP responses received by the client. This option can also be set through Uppy’s tus plugin.

Note that post-create cannot change the HTTP response because it’s emitted when tusd has already sent the response for the creation request.

You also can modify the meta data, but clients are currently not notified of changed meta data. A client would have to manually send a HEAD request to learn about new/changed metadata.

I hope this helps!

Hello,

thank you for your response. Using the onBeforeResponse callback to receive the changes from the pre-create hook makes sense, thank you!

After managing to set the meta data in the hook and change the response,
I tried using the upload-success hooks from uppy or the onAfterResponse functions with medium success to parse the Upload-Metadata header. It seems they expose the headers also depending on data in local storage (sending HEAD / PATCH requests instead of POST)?

I also saw a solution with the additional HEAD request from the client, but wanted to avoid that - as its one more point of possible failure with stable network conditions.

For now I also got an apparently stable solution working with removeFingerprintOnSuccess: true and using the pre-finish hook. Do you have any optimisation suggestions?

it mainly looks like this - I set metadata in the pre-create hook like this - usable for all succeeding hooks:

return context.json({
      ChangeFileInfo: {
        ID: uploadId, // overwrites tusd fileId - must be unique
        MetaData: {
          // visible in  -> head /files/:id?
          ...uploadData.MetaData,
          // pass fileId + uploadId to client and other hooks
          uploadId: uploadId,
          fileId: fileId,
        },
      },
      HTTPResponse: {
        Header: {
          "X-File-Id": fileId, // visible in -> post /files?
        },
      },
    });

Send it to the client in the pre-finish hook:

return context.json({
      HTTPResponse: {
        Header: {
          "X-File-Id": fileId, // visible in -> post /files?
        },
      },
    });

And retrieve it in the client like this + merge it with the client file metadata:

uppy.on<"upload-success">("upload-success", (file, response) => {
    // assume X-File-Id header is set in pre-finish hook, which needs to be manually enabled!
    const fileId = response.body.xhr.getResponseHeader("X-File-Id");

    if (!fileId) {
      console.warn("fileId is empty");
      return;
    }

    try {
      // merge server metadata with file.meta
      uppy.setFileMeta(file.id, { ...file.meta, fileId });
      return;
    } catch (error) {
      console.error(`error handling X-File-Id: ${error}`);
    }
  });

Thank you!