Gagan
Gagan

Reputation: 41

Send file to NestJS GraphQL from Nextjs apollo client

I'm trying to send an array of Files from the Nextjs Apollo client to the Nestjs GraphQL server. But the problem is I'm getting an array of empty objects at the backend I verified this by sending the data back to the frontend without any processing like below.

@Mutation(() => TaskResponseToUser)
  createTask(@Args('createTaskDto') createTaskDto: CreateTaskDto) {
    console.log('se');
    return this.taskService.create(createTaskDto);
  }

async create(createTaskDto: CreateTaskDto): Promise<TaskResponseToUser> {
    console.log(createTaskDto.attachments);
    // Here also I'm getting an array of empty objects like
    // [{},{}]
    return {
      message: 'Task created.',
      status: true,
      data: createTaskDto,
    };
  }

so as you can see from the above code I'm just sending back whatever data I get from the front end. Below are the types I have used for your reference

@InputType()
export class CreateTaskDto {
  @Field(() => String)
  name: string;
  @Field()
  priority: string;
  @Field(() => [String], { nullable: true })
  label?: [string];
  @Field({ nullable: true })
  owner?: string;
  @Field({ nullable: true })
  assignee?: string;
  @Field({ nullable: true })
  dueDate?: string;
  @Field(() => [GraphQLUpload], { nullable: true })
  attachments?: [Upload];
  @Field({ nullable: true })
  description?: string;
}

@ObjectType()
export class CreateTask {
  @Field(() => String)
  name: string;

  @Field()
  priority: string;

  @Field(() => [String], { nullable: true })
  label?: [string];

  @Field({ nullable: true })
  owner?: string;

  @Field({ nullable: true })
  assignee?: string;

  @Field({ nullable: true })
  dueDate?: string;

  @Field(() => AnyType, { nullable: true })
  attachments?: any;

  @Field({ nullable: true })
  description?: string;
}

@ObjectType()
export class TaskResponseToUser {
  @Field(() => String)
  message: string;

  @Field()
  status: boolean;

  @Field({ nullable: true })
  data?: CreateTask;
}

const AnyType = new GraphQLScalarType({
  name: 'Any',
  description: 'Represents any type in GraphQL',
  serialize: (value: any) => value,
  parseValue: (value: any) => value,
});

Here the AnyType, I found this from the stack over-flow answer to set a field as any in Nestjs GraphQL.

Now I will provide the code from front end

function saveTask() {
    const createTaskDto = {
      name: title,
      priority,
      label: labels,
      owner,
      assignee,
      dueDate,
      attachments: filesSelected,
      description
    };
    console.log(createTaskDto);
    if (title) {
      console.log('loading start');
      createTask({ variables: { createTaskDto } })
        .then(res => {
          console.log(res);
        })
        .catch(err => {
          console.log(err);
        })
        .finally(() => {
          console.log('loading end');
        });
    }
  }

Here filesSelected is an array of selected files. And in the first console console.log(createTaskDto); I'm able to see the files selected like below

enter image description here

but I'm getting an error like the one below when I'm making a mutation call

enter image description here

But if I make the attachments field as type any like below

@InputType()
export class CreateTaskDto {
  @Field(() => String)
  name: string;
  @Field()
  priority: string;
  @Field(() => [String], { nullable: true })
  label?: [string];
  @Field({ nullable: true })
  owner?: string;
  @Field({ nullable: true })
  assignee?: string;
  @Field({ nullable: true })
  dueDate?: string;
  @Field(() => AnyType, { nullable: true })
  attachments?: any;
  @Field({ nullable: true })
  description?: string;
}

I won't get the error like the above but I will get an empty array of objects which clearly indicates that the server is not receiving the files that I'm sending from the client/frontend

enter image description here

I tried exploring some of the already existing solutions in Stack Overflow and YouTube but none of it is working in my case. Your support will be appreciated 🙏🏻🙏🏻🙏🏻. I can provide any additional details you want.

Upvotes: 1

Views: 108

Answers (1)

andres martinez
andres martinez

Reputation: 1439

maybe later but the soluction can be use createUploadLink in your ApolloClient init, for ex:

import createUploadLink  from 'apollo-upload-client/createUploadLink.mjs';

const httpLink = createUploadLink({
  uri: process.env.API_URL,
});
...
const authLink = setContext((_, { headers }) => {
  const token = localStorage.getItem('token');
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
      type: 'admin'
    }
  }
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
});

Upvotes: 0

Related Questions