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

How can we handle multi-part request to add "file" in the request? #104

Open
wangmir opened this issue Aug 4, 2023 · 3 comments
Open

How can we handle multi-part request to add "file" in the request? #104

wangmir opened this issue Aug 4, 2023 · 3 comments

Comments

@wangmir
Copy link

wangmir commented Aug 4, 2023

Same as title.

When I wanna send file with Upload scalar, (https://gqlgen.com/reference/file-upload/)
How can we send this request?

Is there any features to support multi-part request on this library? or should I manually add that.

@hgiasac
Copy link

hgiasac commented Aug 5, 2023

Hi @wangmir ,

This library only supports JSON content type. I have no idea if there is another supported graphql client in Go. However, you can use a plain HTTP client to write a simple request with mime/multipart body.

@wangmir
Copy link
Author

wangmir commented Aug 8, 2023

Hi @hgiasac ,

Yes, but I just wanted to utilize the rich functionalities of this library.

When I check the code, I think we can still reuse some of the code, and maybe similar to the requestModifier approach, we can make a custom byte buffer on this.

from below code,

// Request the common method that send graphql request
func (c *Client) request(ctx context.Context, query string, variables map[string]interface{}, options ...Option) ([]byte, *http.Response, io.Reader, Errors) {
	in := GraphQLRequestPayload{
		Query:     query,
		Variables: variables,
	}
	var buf bytes.Buffer
	err := json.NewEncoder(&buf).Encode(in)
	if err != nil {
		return nil, nil, nil, Errors{newError(ErrGraphQLEncode, err)}
	}

	reqReader := bytes.NewReader(buf.Bytes())
	request, err := http.NewRequestWithContext(ctx, http.MethodPost, c.url, reqReader)
	if err != nil {
		e := newError(ErrRequestError, fmt.Errorf("problem constructing request: %w", err))
		if c.debug {
			e = e.withRequest(request, reqReader)
		}
		return nil, nil, nil, Errors{e}
	}
	request.Header.Add("Content-Type", "application/json")

	if c.requestModifier != nil {
		c.requestModifier(request)
	}

	resp, err := c.httpClient.Do(request)
	// ... rest of the code    
}

We can make the below part as the default byte buffer writer. The input will be GraphQLRequestPayload

	var buf bytes.Buffer
	err := json.NewEncoder(&buf).Encode(in)
	if err != nil {
		return nil, nil, nil, Errors{newError(ErrGraphQLEncode, err)}
	}

And, when I want to make multi-part request, then we can just customize this byte buffer to do something like,

var b bytes.Buffer
	w := multipart.NewWriter(&b)

	// Add the query and variables fields
	fw, err := w.CreateFormField("operations")
	if err != nil {
		fmt.Println("Error creating form field: ", err)
		return
	}
	_, _ = fw.Write([]byte(`{"query":"mutation ($input: PostInput!) { createPost(input: $input) { id, title, fileUrl } }","variables":{"input":{"title":"My Title","file":null}}}`))

	fw, err = w.CreateFormField("map")
	if err != nil {
		fmt.Println("Error creating form field: ", err)
		return
	}
	_, _ = fw.Write([]byte(`{"0":["variables.input.file"]}`))

	// Add the file field
	file, err := os.Open(tmpFile.Name())
	if err != nil {
		fmt.Println("Error opening file: ", err)
		return
	}
	defer file.Close()

	fw, err = w.CreateFormFile("0", tmpFile.Name())
	if err != nil {
		fmt.Println("Error creating form file: ", err)
		return
	}
	_, _ = io.Copy(fw, file)

	// Don't forget to close the multipart writer.
	w.Close()

How about that?

If u agree, then I can make a PR to fix this.

@hgiasac
Copy link

hgiasac commented Aug 8, 2023

I get your idea. Feel free to make a PR.
However, you need to make sure the change doesn't break the current interface and API design.

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