#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
? обновить FormData2. да, вы правы, я сделал это для отладки, чтобы пропустить один шаг и сразу начать загрузку.
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)
}
Теперь это работает как шарм.