-
-
Notifications
You must be signed in to change notification settings - Fork 676
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
File upload #37
Comments
Hi, Any news about this feature ? I tried using https://github.com/jaydenseric/apollo-upload-server, i configured a upload resolver like this :
But i've got this error : How to fix this error ? |
https://19majkel94.github.io/type-graphql/docs/scalars.html#custom-scalars You need to provide the scalar type to the async upload(@Arg('file', type => GraphQLUpload) file: Upload): Promise<Media> { |
Thanks @19majkel94 it works |
@19majkel94 where do you import TS type Upload from? |
@danpaugo declare module "apollo-upload-server" {
import { GraphQLScalarType } from "graphql";
import { RequestHandler } from "express";
import { Readable } from "stream";
export interface UploadMiddlewareOptions {
maxFieldSize?: number;
maxFileSize?: number;
maxFiles?: number;
}
export interface Upload {
stream: Readable;
filename: string;
mimetype: string;
encoding: string;
}
export const GraphQLUpload: GraphQLScalarType;
export function apolloUploadExpress(
options?: UploadMiddlewareOptions,
): RequestHandler;
} I will try to upload this definition to DefinitelyTyped repo to make |
Hi , i still experience troubles with it the package now renamed graphql-upload should still be working but i keep having
issue despite the fact that i used the example shown above...it is like tsnode completely ignores the declaration files. |
Here is the error i keep having. I use apollo-server 2.3.1 which comes embedded with graphql-upload 5new name for apollo-server-upload).
Can you help me please? |
It's not a problem with TypeGraphQL itself. |
@19majkel94 thank you for replying. |
@daviddlv have you a example? for upload with scalar on type-graphql? |
@johinsDev , here an example of my resolver : |
thanks, its cool. |
I put the FileInput file in the gist |
I tried to use your gist, but I'm getting
Here's the js output:
|
@laukaichung
the |
hi @19majkel94 , i have issue,, with arg type of array, @ArgsType()
export class XArg {
@Field()
name: string;
@Field({ nullable: true })
value?: string;
} // resolver
@Mutation(returns => Response)
async xCreate(
@Ctx() context: Context,
@Arg("xarr") xarr: Array<XArg>
): Promise<ResponseInterface> {} Error: thanks before |
|
Working solution for me: import { Resolver, Mutation, Arg } from 'type-graphql'
import { GraphQLUpload, FileUpload } from 'graphql-upload'
import os from 'os'
import { createWriteStream } from 'fs'
import path from 'path'
@Resolver()
export default class SharedResolver {
@Mutation(() => ImageResource)
async uploadImage(
@Arg('file', () => GraphQLUpload)
file: FileUpload
): Promise<ImageResource> {
const { createReadStream, filename } = await file
const destinationPath = path.join(os.tmpdir(), filename)
const url = await new Promise((res, rej) =>
createReadStream()
.pipe(createWriteStream(destinationPath))
.on('error', rej)
.on('finish', () => {
// Do your custom business logic
// Delete the tmp file uploaded
unlink(destinationPath, () => {
res('your image url..')
})
})
)
return {
url
}
}
}
|
Thank you for proposed solution @andfk @daviddlv . It seems to be working until I try to upload more than 10 files at once. In that case I am getting this warning:
My resolver looks like this: const fs = require('fs');
import { UploadResult } from '../graphql/models/file';
import { GraphQLUpload, FileUpload } from 'graphql-upload';
import { Resolver, Mutation, Arg } from 'type-graphql';
import isArray from 'lodash/isArray';
@Resolver()
class FileResolver {
@Mutation(() => UploadResult)
async fileUpload(@Arg('fileInput', () => GraphQLUpload) fileInput: FileUpload): Promise<UploadResult> {
let readableStreams = [];
if (isArray(fileInput)) {
readableStreams = await Promise.all(fileInput);
} else {
readableStreams[0] = await fileInput;
}
const pipedStreams = readableStreams.map((readStreamInstance) => {
const { filename, createReadStream } = readStreamInstance;
const writableStream = fs.createWriteStream(`./${filename}`, { autoClose: true });
return new Promise<string>((resolve, reject) => {
createReadStream()
.pipe(writableStream)
.on('error', (error: any) => {
reject(error);
})
.on('finish', () => {
resolve(filename);
});
})
});
const results = await Promise.all(pipedStreams);
return {
uploaded: results
}
}
} The warning gets fired even if I comment-out the whole resolver-function body and just return some random string array. So I suspect that the error is not coming from the resolver itself. It's rather coming from some underlying implementation. Does anybody has similar problem? |
So the warning is coming from eventemitter which is used by nodejs streams. You can bypass the warning by |
Would love to use this, but when I tried I got this error message: This happens when I try to set the |
Apollo Server version? Apolo + express, + koa ...? |
Hey guys, @andfk implementation does not work for me. It fails with this message: This is what my resolver looks like: import { Resolver, Mutation, Arg, Int } from 'type-graphql';
import { GraphQLUpload, FileUpload } from 'graphql-upload';
@Resolver()
export class UploadResolver {
@Mutation(_ => Int)
singleUpload(@Arg('file', () => GraphQLUpload) file: FileUpload) {
console.log(file);
return 3;
}
} This is the query I execute (I have also tried in the app with same result): curl localhost:3333/graphql \
-F operations='{ "query": "mutation ($file: Upload!) { singleUpload(file: $file) }", "variables": { "file": null } }' \
-F map='{ "0": ["variables.file"] }' \
-F [email protected]
{
"errors": [
{
"message":"Variable \"$file\" got invalid value {}; Expected type Upload. Upload value invalid.",
"locations":[{"line":1,"column":11}],
"extensions":{"code":"INTERNAL_SERVER_ERROR",
"exception": {
"message":"Upload value invalid.",
"stacktrace":[
"GraphQLError: Upload value invalid.",
" at GraphQLScalarType.parseValue (/project/node_modules/graphql-upload/lib/GraphQLUpload.js:66:11)",
" at coerceInputValueImpl
[-- snip --] The relevant dependencies as follows:
Am I missing something? FWIW, here is the React implementation of upload, that returns the same error: import React from 'react';
import { useApolloClient, useMutation } from '@apollo/react-hooks';
import gql from 'graphql-tag';
const SINGLE_UPLOAD_MUTATION = gql`
mutation singleUpload($file: Upload!) {
singleUpload(file: $file)
}
`;
export const UploadFile = () => {
const [uploadFileMutation] = useMutation(SINGLE_UPLOAD_MUTATION);
const apolloClient = useApolloClient();
const onChange = ({
target: {
validity,
files: [file]
}
}) =>
validity.valid &&
uploadFileMutation({ variables: { file } }).then(() => {
apolloClient.resetStore();
});
return <input type="file" required onChange={onChange} />;
}; |
@naishe have you added the express middleware? |
Yes, I like this: const app = express();
// -- snip --
apolloServer.applyMiddleware({ app }); I think I figured the problem. import { Resolver, Mutation, Arg, Int } from 'type-graphql';
import { GraphQLUpload } from 'apollo-server-express';
export interface FileUpload {
filename: string;
mimetype: string;
encoding: string;
createReadStream(): ReadStream;
}
@Resolver()
export class UploadResolver {
@Mutation(_ => Int)
async singleUpload(@Arg('file', () => GraphQLUpload) file: FileUpload) {
console.log(file);
return 4; // ideally, you'd return something sensible like an URL
} |
@hemedani
|
I finally think I have tested all possible here posted solutions, but end up all the time with this error. Has anybody the same problem or is it just me?
Edit: NVM, it came from another Module, where I used Buffer as type 🤦♂️ @theerfan just use |
Please help I am getting "Variable "$file" got invalid value {}; Upload value invalid." when calling mutation from apollo client
|
Solution found: |
Not working for me on Node.js v14.6.0. Have basically tried every combination, but keep getting the following error:
Running the following cURL command (notice how "operations" is clearly specified):
Resolver
Any ideas? EDIT: I'm an idiot, turns out I had accidentally put the |
Great examples here. My question is around a multi-part form submission. Do you have multiple Args in this case, or create an input with a property of GraphQLUpload ? |
Hello guys, I am having trouble to get the file upload working. Only a fraction of file gets uploaded. And my mutation resolver returning null instead of boolean. // PostResolver.ts
@Mutation(() => Boolean)
@UseMiddleware(isAuth)
async addPost(
@Arg('file', () => GraphQLUpload)
file: FileUpload
): Promise<boolean> {
const { filename, createReadStream } = file;
console.log(file);
const uploadTime = new Date().toISOString();
const pathName = path.join(
__dirname,
`../../images/${uploadTime}_${filename}`
);
return new Promise((resolve, reject) =>
createReadStream()
.pipe(createWriteStream(pathName, { autoClose: true }))
.on('finish', () => resolve(true))
.on('error', () => reject(false))
);
} A help will be appreciated. 🙏 |
@aseerkt I have the same problem, finally I use sharp to save the file in the server. const getBuffer = (file: FileUpload) => {
const stream = file.createReadStream();
return new Promise<Buffer>((resolve, reject) => {
const buffers: Buffer[] = [];
stream.on('error', (error) => reject(error));
stream.on('data', (data: Buffer) => buffers.push(data));
stream.on('end', () => resolve(Buffer.concat(buffers)));
});
};
const imageBuffer = await getBuffer(file);
await sharp(imageBuffer).toFile(`uploads/images/${image.fileName()}`); |
How can we use with with form data with other fields. For example: |
The examples above all gibe me the following error: |
As @hemedani pointed out, try setting |
|
check this link https://stackoverflow.com/questions/60059940/graphql-apollo-upload-in-nestjs-returns-invalid-value |
I suspect your problem is around your read and write streams, I don't think
it has to do with typegraphql
and uploading files ?
I read the files in as follows - but I write to S3 bucket (setting the body
using createReadStream() which doesn't really help you for that). I'd
look into making sure you're using the create read/write streams
correctly. Some snippets from how I do it:
@arg('files', () => GraphQLUpload) files: FileUpload[]
export interface FileUpload {
filename: string;
mimetype: string;
encoding: string;
createReadStream(): ReadStream;
}
const readableStreams = await Promise.all(files);
const pipedStreams = readableStreams.map((readStreamInstance) => {
const { filename, createReadStream } = readStreamInstance;
…On Fri, Sep 17, 2021 at 5:16 AM SedkiDataBank ***@***.***> wrote:
I am getting an unresolved error, anyone can take a look? tyvm
{
"errors": [
{
"message": "Unexpected error value: false",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"addCandidateResume"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: Unexpected error value: false",
" at asErrorInstance (/Users/sed9ydatabank/Documents/real-deal/ovice-rms/ovice-rms-server/node_modules/graphql/execution/execute.js:516:10)",
" at processTicksAndRejections (internal/process/task_queues.js:95:5)"
]
}
}
}
],
"data": null
}
import { Resolver, Mutation, Arg } from "type-graphql";import { GraphQLUpload, FileUpload } from "graphql-upload";import { createWriteStream } from "fs";
@resolver()export class CandidateResumeResolver {
@mutation(() => Boolean)
async addCandidateResume(
@arg("resume", () => GraphQLUpload)
{ createReadStream, filename }: FileUpload
): Promise<boolean> {
return new Promise(async (resolve, reject) =>
createReadStream()
.pipe(createWriteStream(__dirname + `/../../../resumes/${filename}`))
.on("finish", () => {
resolve(true);
})
.on("error", () => reject(false))
);
}}
const apolloServer = new ApolloServer({
schema,
uploads: false
});
app.use(graphqlUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }));
I have created a resumes folder but I am getting this error.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#37 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABAKNFBF5PKIJKSO6TR2PLUCMBPTANCNFSM4ETHD66Q>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
|
Hi guys i have a similar problem when I load images with a resolver in GraphQL using a inputType class in NestJS, I get 0-byte files when i upload to s3. mutation: @Mutation(() => Course)
async addResources(
@Args({ name: 'input', type: () => CreateResources }) input: CreateResources,
@CurrentUser() user: User
) {
const type = EXTRARESOURCES;
const result = await this.courseService.addExtraResources(
user,
input,
type
);
if (!result) errorInvalidInput(type);
return result;
} inputType files arrive with 0 bytes @InputType()
export class CreateResources {
@IsOptional()
@Field(() => [CreateResourceLinkInput], { nullable: true })
links: CreateResourceLinkInput[];
@IsOptional()
@Field(() => [CreateResourceVideoInput], { nullable: true })
videos: CreateResourceVideoInput[];
@IsOptional()
@Field(() => [GraphQLUpload], { nullable: true })
documents: Promise<[FileUpload]>;
@IsOptional()
@Field(() => [GraphQLUpload], { nullable: true })
images: Promise<[FileUpload]>;
} All as args works fine @Mutation(() => Course)
async AddResources(
@Args({ name: 'links', type: () => [CreateResourceLinkInput], nullable: true }) links: [CreateResourceLinkInput],
@Args({ name: 'videos', type: () => [CreateResourceVideoInput], nullable: true }) videos: [CreateResourceVideoInput],
@Args({ name: 'documents', type: () => [GraphQLUpload], nullable: true }) documents: [FileUpload],
@Args({ name: 'images', type: () => [GraphQLUpload], nullable: true }) images: [FileUpload],
@CurrentUser() user: User
) {
const type =EXTRARESOURCES;
const input = {
links,
videos,
documents,
images
};
const result = await this.courseService.addExtraResources(
user,
input,
type
);
if (!result) errorInvalidInput(type);
return result;
} |
@SergioSuarezDev So you should ask on Nest github/discord as their implementation is quite different from TypeGraphQL. |
Since apollo-upload-server is deprecated, how can we move on with apollo-upload did anyone find a way dealing with apollo-upload when it comes to file uploads ? |
Packages: "@apollo/server": "^4.3.0",
"fastify": "^4.11.0",
"@as-integrations/fastify": "^1.2.0",
"graphql-upload-ts": "^2.0.5", I use Mutation import { FileUpload, GraphQLUpload } from 'graphql-upload-ts'
@Mutation(() => Boolean)
async uploadService(
@Arg('picture', () => GraphQLUpload)
{ createReadStream, filename }: FileUpload
) {
return new Promise(async (resolve, reject) =>
createReadStream()
.pipe(createWriteStream(__dirname + '/' + filename))
.on('finish', () => resolve(true))
.on('error', () => reject(false)),
)
} Receiver error: {
"errors": [
{
"message": "Variable \"$picture\" got invalid value {}; Upload value invalid.",
"locations": [
{
"line": 1,
"column": 24
}
],
"extensions": {
"code": "BAD_USER_INPUT",
"stacktrace": [
"GraphQLError: Variable \"$picture\" got invalid value {}; Upload value invalid.",
" at /home/psoeng/www/pso-easynr10/node_modules/graphql/execution/values.js:147:11",
" at coerceInputValueImpl (/home/psoeng/www/pso-easynr10/node_modules/graphql/utilities/coerceInputValue.js:154:9)",
" at coerceInputValueImpl (/home/psoeng/www/pso-easynr10/node_modules/graphql/utilities/coerceInputValue.js:49:14)",
" at coerceInputValue (/home/psoeng/www/pso-easynr10/node_modules/graphql/utilities/coerceInputValue.js:32:10)",
" at coerceVariableValues (/home/psoeng/www/pso-easynr10/node_modules/graphql/execution/values.js:132:69)",
" at getVariableValues (/home/psoeng/www/pso-easynr10/node_modules/graphql/execution/values.js:45:21)",
" at buildExecutionContext (/home/psoeng/www/pso-easynr10/node_modules/graphql/execution/execute.js:280:63)",
" at execute (/home/psoeng/www/pso-easynr10/node_modules/graphql/execution/execute.js:116:22)",
" at executeIncrementally (/home/psoeng/www/pso-easynr10/node_modules/@apollo/server/src/incrementalDeliveryPolyfill.ts:109:17)",
" at processTicksAndRejections (node:internal/process/task_queues:95:5)"
]
}
}
]
} All solutions posted here, dont work for me. |
@Tjerk-Haaye-Henricus You finded any solutions for your problem? |
Hey @jdgabriel 👋 Yes i found a way. I'm using this combination now:
I hope that i got all things covered :D |
@Tjerk-Haaye-Henricus, thanks for the answer. GraphQLError: "Variable \"$picture\" got invalid value { path: \"myDoc.docx\" }; Upload value invalid." Packages: "@apollo/server": "^4.3.0",
"fastify": "^4.11.0",
"@as-integrations/fastify": "^1.2.0",
"graphql-upload": "^16.0.2" I'm a beginner in graphql, I can't find solutions. |
Solve my problem with fastify: Packages: "fastify": "^4.11.0",
"@fastify/multipart": "^7.4.0",
"graphql-upload-ts": "^2.0.5", import multiPart from "@fastify/multipart"
import { processRequest } from "graphql-upload-ts"
--
// server.ts
await server.register(multiPart) // Add Multipart plugin
server.addHook('preValidation', async (request, reply) => {
if (!request.isMultipart()) return // Valid if is multipart header
// Process all Files
request.body = await processRequest(request.raw, reply.raw, {
maxFileSize: 1e20, // Max file size example, change it
maxFiles: 20, // Max files example, change it
})
}) // Resolver
import { FileUpload, GraphQLUpload } from 'graphql-upload-ts'
--
@Mutation(() => Boolean)
async addProfilePicture(
@Arg('picture', () => [GraphQLUpload]) picture: FileUpload[],
) {
try {
picture.map(async (pic) => {
const { filename, createReadStream } = await pic
return new Promise((resolve, reject) =>
createReadStream()
.pipe(createWriteStream(`./public/${filename}`))
.on('finish', () => resolve(true))
.on('error', () => reject(false)),
)
})
return true
} catch (error) {
return false
}
} |
@jdgabriel Can you share all your server.ts content? |
Integration with https://github.com/jaydenseric/apollo-upload-server
The text was updated successfully, but these errors were encountered: