Search code examples
node.jsgraphqlfsapollo

NodeJS: Get File, not Buffer


I have set up a mutation on my apollo GraphQL server with graphql-upload (or apollo-upload-server) to receive a file from the client, and now I'm trying to write a test for this mutation but I'm not sure how to attach the actual file to my mock request.

On my client I have an input type="file" and on upload event I extract the file

async upload(event) {
  const files = event.target.files || event.dataTransfer.files;
  const file = files[0]; // type of file is File
  await apollo.mutate({
    mutation: gql`
      mutation UploadFile($file: Upload) {
        uploadFile(file: $file)
      }
    `,
    variables: { file },
  })
}

So far all is good. But I would like to write a test case on my server as well.

This is my problem

On my server, I would like to mimic the client uploading the file. But I can't find how I'd access the actual file from within NodeJS.

I've tried:

const file = fs.readFileSync('path/to/test-file.csv');

But fs returns a Buffer, not of type File which also contains meta-data, such as mimetype, name, lastModified properties for instance.

How do I get the actual File object and not the Buffer?

Thanks!


Solution

  • There is no File class in Node.js. There is not even, as of writing this, any other class that would, say, encapsulate accessing the MIME type, contents, and name of a file. You will have to use "lower level" methods to accomplish what you want:

    1. There is the fs.readFileSync that gets you the file's contents from a file descriptor or file path.
    2. There is the fs.lstatSync and fs.fstatSync that [synchroniously, like with readFileSync] get you some of the attributes you want, in particular the "last modified timestamp" of the file.

    There is no definite accepted way to obtain a file's MIME type -- even though some MIME types for some kinds of data are standardized, heuristical analysis of the contents is typically applied to determine the MIME type of a file. For instance, for an SVG file (typically *.svg) which is also a valid XML file, you'd want to make sure the file is parseable as XML in so far as to determine that the root "svg" element belongs to the SVG namespace by comparing the declared namespace URI to the known SVG element namespace, before positively asserting that the file is of the image/svg+xml MIME type. This kind of approach -- some analysis of actual file contents -- would apply to any case of determining a MIME type, if one wants to be certain.

    Now, most Web servers just use the file's extension as a key to a MIME type map -- for instance, all *.gif files are said to be of image/gif MIME type, even if there is garbage or plain text in them. That's because neither the Web server nor the client typically needs heuristical analysis -- if the file that is assumed to be a GIF is actually garbage, the client will abort rendering or render garbage, but the responsibility to ensure the file contents are valid, lies on whoever owns the file, not the Web server, and the latter does not care much for the contents anyway, it only serves content, parsing it isn't really its responsibility normally (not for "asset" files). The real reason, however, is performance, of course -- given how heuristical analysis is more often than not more costly than just deciding the MIME type based on file extension, the latter method is preferred.