Не была предоставлена переменная «$picture» требуемого типа «Загрузить!»

#node.js #express #graphql #next.js #apollo-client

#node.js #экспресс #graphql #next.js #apollo-клиент

Вопрос:

Я пытаюсь загрузить файл с помощью apollo-upload-client из Next.js приложение к Node.js серверная часть с использованием graphql.

Моя конфигурация клиента Apollo

 const createClient = (ctx: NextPageContext) =>
new ApolloClient({
  credentials: "include",
  headers: {
    cookie:
      (typeof window === "undefined"
        ? ctx?.req?.headers.cookie
        : undefined) || "",
  },
  cache: new InMemoryCache(),
  link: createUploadLink({uri:'http://localhost:4000/graphql', credentials:"include"})
});
 

Мой экспресс-распознаватель с TypeORM

 @Resolver()
export class ProfilePictureResolver {
  @Mutation(() => Boolean)
  async addProfilePicture(@Arg("picture", () => GraphQLUpload)
  {
    createReadStream,
    filename
  }: Upload): Promise<boolean> {
    return new Promise(async (resolve, reject) =>
      createReadStream()
        .pipe(createWriteStream(__dirname   `/../../../images/${filename}`))
        .on("finish", () => resolve(true))
        .on("error", () => reject(false))
    );
  }
}

 

Страница

 const Profile:React.FC<IProps> = () => {

  const user = useSelector(state => state.user);
  const [file, setFileToUpload] = useState(null);
  const [mutate, {loading}] = useMutation(UPLOAD_IMAGE_MUTATION);


   function onChange({
    target: {
      validity,
      files: [file],
    },
  }) {
    if (validity.valid) mutate({ variables: { picture: file } });
  }

  const onSubmit = async (e) =>{
    e.preventDefault();
    console.log(file)
    const response = await mutate({
          variables: {picture: file}
    });


  }

    return (
        <Box mt={20} pl={30} pr={30}>
          <Header>
            Edit Profile
          </Header>
          <input onChange={onChange} type="file" placeholder="photo" />
          <button onClick={(e)=>onSubmit(e)}>Submit</button>
        </Box>
      
    )
};

 

FormData

——WebKitFormBoundary3bcoEmOQWM0eUhCG Содержимое-Расположение: форма-данные; имя =»операции»

{«OperationName»:»addProfilePicture»,»variables»:{«picture»: null},»query»: «мутация addProfilePicture($picture: Загрузить!) {n addProfilePicture(picture: $picture) n}n»} ——Содержимое WebKitFormBoundary3bcoEmOQWM0eUhCG-Расположение: форма-данные; имя = «карта»

{«1»:[«variables.picture»]} ——WebKitFormBoundary3bcoEmOQWM0eUhCG Расположение содержимого: форма-данные; имя =»1″; имя файла =»73387406_149357266327075_4919835380817576193_n.jpg » Тип содержимого: изображение / jpeg

——WebKitFormBoundary3bcoEmOQWM0eUhCG—

Перед вызовом мутации в консоли я вижу, что файл присутствует. Что я делаю не так?

Обновление: я исправил мутацию на стороне клиента, изменил файл на picture:file. Теперь у меня другая ошибка:

Переменная «$picture» получила недопустимое значение {}; Значение загрузки недопустимо.

Обновление 2:

Вот как выглядит мой запрос, может помочь

js export const UPLOAD_IMAGE_MUTATION = gql` mutation addProfilePicture($picture: Upload!) { addProfilePicture(picture: $picture) } `;

РЕШЕНИЕ

Я подумал, что действительно что-то не так с моим распознавателем сервера apollo

Я изменил старый распознаватель (см. Выше) на этот:

  uploadFile: async (_, { file }) => {
      const { createReadStream, filename } = await file;

      await new Promise(res =>
        createReadStream()
          .pipe(createWriteStream(path.join(__dirname, "../images", filename)))
          .on("close", res)
      );

      files.push(filename);

      return true;
    },
 

Итак, как вы видите, я больше не использую загрузку graphql, а также я изменил свою мутацию клиента обратно на

mutate({ variables: { file } }

И новый запрос мутации:

   mutation UploadFile($file: Upload!) {
    uploadFile(file: $file)
  }
 

Теперь это работает как шарм. Обращение закрыто.

Комментарии:

1. mutate вызывается дважды? должно быть setFileToUpload(file) в onChange ? обновить FormData

2. да, вы правы, я сделал это для отладки, чтобы пропустить один шаг и сразу начать загрузку.

3. все еще variables.file в FormData — показать спецификации серверной части для этой мутации, каково требуемое имя аргумента мутации — file или picture ?

4. требуется — picture

5. … снова … обновить FormData …. правильно ли BE / API поддерживает загрузку?

Ответ №1:

Как указывает ошибка, ваша операция включает в себя переменную с именем $picture , но вы не указали такую переменную. При вызове mutate единственной переменной, которую вы предоставляете, является та, которая называется $file . Вместо этого вы должны сделать:

 const response = await mutate({
  variables: { picture: file },
});
 

Комментарии:

1. Верно, моя ошибка. Но все еще не работает. Теперь я получаю это: "Variable "$picture" got invalid value {}; Upload value invalid."

Ответ №2:

Я подумал, что действительно что-то не так с моим распознавателем сервера apollo

Я изменил старый распознаватель из вопроса по этому вопросу:

  uploadFile: async (_, { file }) => {
      const { createReadStream, filename } = await file;

      await new Promise(res =>
        createReadStream()
          .pipe(createWriteStream(path.join(__dirname, "../images", filename)))
          .on("close", res)
      );

      files.push(filename);

      return true;
    },
 

Итак, как вы видите, я больше не использую загрузку graphql, а также я изменил свою мутацию клиента обратно на

mutate({ variables: { file } }

И новый запрос мутации:

   mutation UploadFile($file: Upload!) {
    uploadFile(file: $file)
  }
 

Теперь это работает как шарм.