Skip to content
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

Strange unawaited file wrapped structure #253

Closed
ssukienn opened this issue Jun 28, 2021 · 1 comment
Closed

Strange unawaited file wrapped structure #253

ssukienn opened this issue Jun 28, 2021 · 1 comment

Comments

@ssukienn
Copy link

ssukienn commented Jun 28, 2021

Hi. I have some problems with the structure of the uploaded file(s).

I integrated this library inside my federated project, the gateway, and example service. On top of that I am using Nest.js framework which is instantiating both mentioned above.

In both services, I turned off the default upload (in ApolloGateway and ApolloServer) by setting uploads: false.
Additionally, I set the graphqlUploadExpress middleware:

...
export class AppModule implements NestModule {
    configure(consumer: MiddlewareConsumer) {
        consumer.apply(graphqlUploadExpress()).forRoutes('graphql');
    }
}

My service federated schema related to uploads looks like:

type Mutation {
    uploadTest(attachment: Upload!, file: UploadModel!): Survey
}

"""The `Upload` scalar type represents a file upload."""
scalar Upload

input UploadModel {
  uploadFile: Upload
}

and resolver:

import { FileUpload, GraphQLUpload } from 'graphql-upload';

@Mutation(() => SomeModel, {
    nullable: true,
})
async uploadTest(
    @Args('file') upload: UploadModel,
    @Args('attachment', { type: () => GraphQLUpload }) attachment: FileUpload,
) {
    const actualFile = await this.resolveFile(attachment);
    const stream = actualFile.createReadStream();
    stream?.on('data', (chunk: Buffer) => console.log(chunk.toString()));
}

async resolveFile(file: any) {
    const awaitedFile = await (file as { promise: Promise<{ file: FileUpload }> }).promise;
    return await (awaitedFile as any).promise;
}

Nest reference: nestjs/graphql#901 (comment)

UploadModel is some input object which takes a file but it doesn't matter if the file is nested inside the input or passed as a direct argument. The actual file containing createReadStream is obtained after some promise shenanigans happening in resolveFile helper.

When looking inside the debugger the actual structure of the attachment is something like:
image
where I have Upload object with file property without the stream and the promise which when awaited consists of { resolve, reject, promise} and after awaiting this second promise (which I thought won't be there and I will get the file thus typing in resolveFile) I actually get the real structure of FileUpload. The file object from the screen on the same level as resolve and reject is not actually there until awaiting the second promise (that's why double promise awaits in resolveFile).

Unfortunately, it will be hard for me to provide some reproducible repo due to the size of the project but maybe someone faced similar issues with strange wrapping and have an idea of what I am doing wrong here?

I am testing it with the Altair with request source like:

------WebKitFormBoundaryMIblSV1Wzt7MZCa7
Content-Disposition: form-data; name="operations"

{"query":"# query someQuery {\n#   me {\n#     tenant {\n#       uuid\n#       logo\n#     }\n#   }\n# }\n\nmutation someMutation($someFile: Upload!) {\n  uploadTest(attachment: $someFile, file: { uploadFile: $someFile }) {\n    uuid\n  }\n}","variables":{"someFile":null},"operationName":"someMutation"}
------WebKitFormBoundaryMIblSV1Wzt7MZCa7
Content-Disposition: form-data; name="map"

{"0":["variables.someFile"]}
------WebKitFormBoundaryMIblSV1Wzt7MZCa7
Content-Disposition: form-data; name="0"; filename="test.txt"
Content-Type: text/plain


------WebKitFormBoundaryMIblSV1Wzt7MZCa7--

Thanks for help.

versions:

graphql-upload: 12.0.0
@types/graphql-upload: 8.0.5

@ssukienn ssukienn changed the title Strange unawaited file structure Strange unawaited file wrapped structure Jun 28, 2021
@jaydenseric
Copy link
Owner

It seems the complexity and source of your problems is Nest, Apollo Server and Gateway; it's better to ask for help from the Nest community or Apollo customer service if you're having difficulty with their products.

Note that for schema stitching some of the tooling that might be present in your project substitutes the GraphQLUpload scalar, because the original scalar is only intended as an input, but they "serialize" (even though a file upload stream can't be serialized to a string like the GraphQL serialization system was originally intended) the value back out to forward it to the next GraphQL API:

https://github.com/ardatan/graphql-tools/blob/eb233dae26f74c45ba74c02edf77ef1975bfbf69/packages/links/src/GraphQLUpload.ts#L4-L22

There is past discussion on this topic you can see in #194 .

Although everything about graphql-upload is documented quite thoroughly in the readme, I'm happy to answer here any questions you may have about just the graphql-upload project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants