Uploading a file to ASP.Net Core via GraphQL

luvforairplanes

Micah Stauffer

Posted on February 9, 2022

Uploading a file to ASP.Net Core via GraphQL

In a recent internal application, I was asked to provide a way to upload a backup to the application. This is a fairly isolated implementation that may useful for others.

Our tech stack looks like:
Server:

  • ASP.Net [Core] 5.0
  • HotChocolate for GraphQL

Client:

  • React with TypeScript
  • Material UI components
  • Apollo JS for GraphQL

Server GraphQL Endpoint

The first step is to put the GraphQL endpoint in place on the server.

public async Task<CompanyBackup> UploadCompanyBackupAsync(
        [Service] IHost host,
        [GraphQLType(typeof(NonNullType<UploadType>))] IFile file) =>
        new CompanyBackup
        {
            Id = "backup"
        };
Enter fullscreen mode Exit fullscreen mode

If you've haven't already been using GraphQL in your project, you will need to register the containing class as a mutational entity. (in this case, Mutations) This registers the GraphQL endpoints and tells HotChocolate which type contains our endpoints. It also tells GraphQL that we would like to post an object of type UploadType to the endpoint.

services.AddGraphQLServer().AddMutationType<Mutations>().AddType<UploadType>();

Configuration Apollo

On the client-side, Apollo needs a bit of configuration to function correctly. A new link must be provided for the binary upload capabilities. To install the required package which contains the new link, run:

npm i apollo-upload-client

and, if you're using TypeScript:

npm i --save-dev @types/apollo-upload-client

Then in your Apollo config file, add these snippets of code:

const uploadLink = createUploadLink({
  uri: '/graphql/'
});
Enter fullscreen mode Exit fullscreen mode

This upload link comes from the package you just installed, and enables Apollo to post binary data to the server.

const uploadVsNonUploadLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition!.name!.value === 'uploadCompanyBackup'
    );
  },
  uploadLink,
  httpLink,
);
Enter fullscreen mode Exit fullscreen mode

This next link determines which link should be used for each transaction. Replace the httpLink variable near the end with your actual HttpLink variable name.
Finally, to activate the split function, provide uploadVsNonUploadLink in your ApolloClient initialization statement for link instead of the httpClient implementation.

Query

Below is the query we'll use to upload the file.

import { gql } from '@apollo/client';

export const UploadBackupMutation = gql`
  mutation uploadCompanyBackup($file: Upload!) {
    uploadCompanyBackup(file: $file) {
      id
    }
  }
`;
Enter fullscreen mode Exit fullscreen mode

The Real Code (JSX)

The mutation hook uses the GraphQL query we just wrote:

const [uploadBackup] = useMutation(UploadBackupMutation);
Enter fullscreen mode Exit fullscreen mode

Below is the UI code that actually allows the user to do the upload. It calls onChange when the input value changes.

<Button component="label" color="primary">
  <AddIcon /> Upload a Backup
  <input type="file" hidden onChange={onChange} />
</Button>
Enter fullscreen mode Exit fullscreen mode

Below is detailed the onChange method. It basically calls the mutation with the variables set. (the file selected)

function onChange({
  target: {
    validity,
    files: [file],
  },
}: any) {
  if (validity.valid)
    uploadBackup({
      variables: {
        file,
        companyId: company.id
      } 
  });
}
Enter fullscreen mode Exit fullscreen mode

For me this took a little to get everything pieced together. If it helped your project I'd appreciate a 👍.

Cheers till next time!

💖 💪 🙅 🚩
luvforairplanes
Micah Stauffer

Posted on February 9, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related