How to validate the filename of an uploaded file in a Sanity schema using the "file" data type.

4 replies
Last updated: Oct 6, 2021
Hello everyone! Has anyone ever done any filename validation in a schema with the "file" data type? I'll be periodically uploading newer versions of files and need to make sure I'm not adding the wrong file in any document.

export default {
    name: 'download',
    title: 'Download',
    type: 'document',
    fields: [
        {
            name: 'name',
            title: 'Name',
            type: 'string',
            validation: (Rule) => Rule.required(),
        },
        {
            name: 'description',
            title: 'Description',
            type: 'string',
        },
        {
            name: 'filename',
            title: 'Filename',
            description: 'This will be the filename which the uploaded file must have.',
            type: 'string',
            validation: (Rule) => Rule.required(),
        },
        {
            name: 'file',
            title: 'File',
            type: 'file',
            validation: (Rule) => Rule.required(),
        },
        {
            name: 'active',
            title: 'Active',
            description: 'Is this download active?',
            type: 'boolean',
            initialValue: true,
        },
    ],
}
If I try to do document level validation, I don't know how to get the original file name. Doing the following only gets me the hashed filename.

validation: (Rule) =>
    Rule.custom((doc) => {
        const matched = doc.filename === doc.file.asset._ref;
        return matched
            ? 'Uploaded filename does not match the expected filename.'
            : true
        return true;
    }),
Oct 4, 2021, 12:00 AM
Hi User! Sorry for the delay responding.
Thankfully, validation can be async, so you can use a client to dereference the file asset and get the filename:


import sanityClient from 'part:@sanity/base/client';

const client = sanityClient.withConfig({ apiVersion: '2021-10-04' });

export default {
  name: 'download',
  title: 'Download',
  type: 'document',
  fields: [
    {
      name: 'name',
      title: 'Name',
      type: 'string',
      validation: (Rule) => Rule.required(),
    },
    {
      name: 'description',
      title: 'Description',
      type: 'string',
    },
    {
      name: 'filename',
      title: 'Filename',
      description: 'This will be the filename which the uploaded file must have.',
      type: 'string',
      validation: (Rule) => Rule.required(),
    },
    {
      name: 'file',
      title: 'File',
      type: 'file',
      validation: Rule => Rule.custom(async (doc, context) => {
        const { _ref } = doc.asset
        const { filename } = context.document
        const originalFilename = await client.fetch(`*[_id == $ref][0].originalFilename`, { ref: _ref })

        return filename === originalFilename ? true : `Uploaded file ${originalFilename} does not match required filename ${filename}`
      }),
    },
    {
      name: 'active',
      title: 'Active',
      description: 'Is this download active?',
      type: 'boolean',
      initialValue: true,
    },
  ],
}
This is using the client to get the original filename of the fileAsset, then it compares it against the filename field (using the
second parameter of
Rule.custom()
). If they match, return
true
. If they don’t, tell the user why.
Oct 5, 2021, 3:51 AM
Thank you so much for this. I would have never thought of doing it that way.
Oct 6, 2021, 3:53 PM
Thank you so much for this. I would have never thought of doing it that way.
Oct 6, 2021, 3:53 PM
No problem, User! Glad that works for you.
Oct 6, 2021, 4:15 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?