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

Add multipart request support #430

Closed
wants to merge 2 commits into from

Conversation

nkonev
Copy link

@nkonev nkonev commented Jun 30, 2022

This PR adds MultipartFile support for WebMVC and FilePart for WebFlux on server side, HttpGraphQlClient, HttpGraphQlTester support on client side.
#69

Test project https://github.com/nkonev/graphql.demo/tree/file-test-harness

@rstoyanchev Please take a look when you get a chance.

P. S. About formatting:
I tried to fix it by installing spring-javaformat 034 jar (as described here https://github.com/spring-io/spring-javaformat), but it reports issues of files out of scope my PR. Can you please apply your configured formatter ?

P. S. S. The next step is to add handlers and coercing(optionally) to Spring Boot.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 30, 2022
@nkonev nkonev changed the base branch from main to 1.0.x June 30, 2022 22:24
@nkonev nkonev changed the title Add MultipartFile support to WebMVC Add MultipartFile support Jun 30, 2022
@nkonev nkonev changed the title Add MultipartFile support Add multipart support Jul 29, 2022
@nkonev nkonev marked this pull request as ready for review July 29, 2022 23:32
@nkonev nkonev changed the title Add multipart support Add http multipart support Jul 29, 2022
@nkonev
Copy link
Author

nkonev commented Aug 4, 2022

cc @bclozel

@nkonev
Copy link
Author

nkonev commented Aug 24, 2022

Would you like to give any feedback ?
@rstoyanchev @bclozel

@bclozel
Copy link
Member

bclozel commented Aug 24, 2022

Sorry we didn't have time to have a deeper look. This is on our radar and we'll let you know once the entire team is back.
Thanks!

@bclozel bclozel added the for: team-attention An issue we need to discuss as a team to make progress label Sep 1, 2022
@bclozel bclozel added type: enhancement A general enhancement in: web Issues related to web handling and removed status: waiting-for-triage An issue we've not yet triaged for: team-attention An issue we need to discuss as a team to make progress labels Sep 22, 2022
@bclozel bclozel added this to the 1.1 Backlog milestone Sep 22, 2022
@nkonev
Copy link
Author

nkonev commented Sep 22, 2022

I can rebase it onto main branch (future 1.1.x).

Any fixes, any explanations, let me know if they are needed.

@bclozel
Copy link
Member

bclozel commented Sep 22, 2022

For full transparency, we've discussed this today and we've scheduled this issue (and #69) to the 1.1 Backlog. We don't think we'll get to it in time for 1.1.0, but this is definitely on our radar. Our existing 1.1 milestones are already quite full and we want to make sure we get this right.

We'd like to spend more time experimenting with this and thinking about ways to address CSRF issues in general. We might evolve this PR, or selectively pick things up from it. In any case, your contribution will be recognized as it should.

@bramklg
Copy link

bramklg commented Dec 6, 2022

Is there any update/eta on this? I see the issue itself is on the 1.2 backlog now that doesn't specify any due date or something.

@sathizhdev
Copy link

we have same file upload via graphQL requirement.... Any update on @nkonev proposed fix? @bclozel

@nkonev
Copy link
Author

nkonev commented Mar 20, 2023

Can we add it to one of 1.2.x milestones ? @bclozel @rstoyanchev

@rstoyanchev
Copy link
Contributor

rstoyanchev commented Mar 20, 2023

@nkonev apologies for the delay in getting back to you.

We've discussed this on the team, and think that file uploads embedded in GraphQL requests adds unnecessary complexity vs using an HTTP endpoint to handle multipart requests. A @MutationMapping method for file uploads would look very similar to a @PostMapping method for the same, and would have the same implementation, but the latter is based on existing standards and support.

Looking at Apollo Server File Upload Best Practices it seems they've evolved their approach, also moving away from the file uploads spec. The article recommends against using file uploads in strong terms, and suggests to separate handling of file uploads from the handling of GraphQL requests for a variety of reasons including security and performance.

Noting what Apollo has done from 3.0 to keep the graphql-upload package external, one alternative would be to explore the option of keeping this as an externally maintained extension. I don't know how easy that would be in terms of the available extensions points, but it's an option to explore.

@nkonev
Copy link
Author

nkonev commented Mar 20, 2023

@rstoyanchev thank you for the explanation and link

@rstoyanchev
Copy link
Contributor

rstoyanchev commented Apr 14, 2023

As per my last comment, we are not going to have multipart uploads support built in, but I want to make sure there is enough flexibility so it can exist independently.

Looking at the PR as a model, on the server side there can be a separate multipart handler that creates a request and passes it down the chain. On the client side, it seems to come down to a slightly customized WebClient call, which would be straight forward without involving GraphQlClient, and the same for testing with WebTestClient. If there is anything specific we could do there, please let us know.

Overall, the code could become simpler if built more explicitly for HTTP, and separate from the main API vs trying to fit into a transport agnostic base. It also connects back to the mismatch between GraphQL being transport agnostic vs multipart uploads being an HTTP only mechanism, and if you must implement the spec, might as well model it more explicitly along those lines.

@rstoyanchev rstoyanchev mentioned this pull request Apr 14, 2023
@nkonev
Copy link
Author

nkonev commented Apr 26, 2023

there can be a separate multipart handler that creates a request

@rstoyanchev
About server. To make it possible to write Multipart GraphQlHttpHandler we need to have access to WebGraphQlRequest's query, operationName, variables. Right now they aren't accessible - they are extracted in the constructor

public WebGraphQlRequest(...
		super(getKey("query", body), getKey("operationName", body), getKey("variables", body),
				getKey("extensions", body), id, locale);

Are you ok to add one more constructor in separate PR ? To make it simpler to write Multipart GraphQlHttpHandler (than here - see MultipartGraphQlRequest - it will gone if we add the that constructor)

	public WebGraphQlRequest(
		URI uri, HttpHeaders headers,
		String query,
		String operationName,
		Map<String, Object> variables,
		Map<String, Object> extensions,
		String id, @Nullable Locale locale) {

		super(query, operationName, variables, extensions, id, locale);

		Assert.notNull(uri, "URI is required'");
		Assert.notNull(headers, "HttpHeaders is required'");

		this.uri = UriComponentsBuilder.fromUri(uri).build(true);
		this.headers = headers;
	}

About client. It's interesting - to just customize WebClient. Indeed, at first glance it looks attractive, because the only meaningful thing is

    @Override
    public Mono<GraphQlResponse> executeFileUpload(GraphQlRequest request) {
        return this.webClient.post()
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_GRAPHQL)
                .body(BodyInserters.fromMultipartData(convertRequestToMultipartData(request)))
                .retrieve()
                .bodyToMono(MAP_TYPE)
                .map(ResponseMapGraphQlResponse::new);
    }

@rstoyanchev
Copy link
Contributor

@nkonev sending another PR with concrete suggestions sounds good.

@rstoyanchev
Copy link
Contributor

Closing this for now as we don't intend to proceed as per my earlier #430 (comment). @nkonev, thanks for all the effort in any case!

@rstoyanchev rstoyanchev removed this from the 1.2 Backlog milestone May 15, 2023
@rstoyanchev rstoyanchev added the status: declined A suggestion or change that we don't feel we should currently apply label May 15, 2023
@rstoyanchev rstoyanchev changed the title Add http multipart support Add multipart request support May 15, 2023
@nkonev
Copy link
Author

nkonev commented May 15, 2023

Yes,
please don't remove pr in order to let me or someone else make this functionality separately, plugin-like

@rstoyanchev
Copy link
Contributor

There is no way to delete a pull request. Is that what you meant? It's just in "closed" instead of "open" state, but it's still possible to search and find.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues related to web handling status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants