go-resty / resty

Simple HTTP and REST client library for Go
MIT License
9.98k stars 705 forks source link

Is there anyway to make multipart formdata has order? #669

Open Sczlog opened 1 year ago

Sczlog commented 1 year ago

I am working with graphql-upload and it's processor must accept one field before any other fields, otherwise it will throw an error. I know that map has no order and should has no order, but if there is anyway to make a raw body of multipart and keep its order?

image

Sczlog commented 1 year ago

Find myself a workaround, use mime/multipart to create body, set raw body and content-type will keep the order.

var bBody bytes.Buffer
writer := multipart.NewWriter(&bBody)

writer.WriteField("firstkey","firstvalue")
writer.WriteField("secondkey","secondvalue")
part, err := writer.CreateFormFile("fieldname", "filename")
if err != nil {
    return nil, err
}
part.Write([]byte("filecontent"))
writer.Close()
request := c.Client.R()
request.SetHeader("Content-Type", writer.FormDataContentType())
request.SetBody(bBody.Bytes())
resp, err := request.Post("endpoint")
jeevatkm commented 1 year ago

@Sczlog Thanks for bringing it up and finding a workaround to move forward. I may think of a way to preserve order.

praem90 commented 1 year ago

Can we add a new method that can accept a slice instead of map and write it to the body in the same order ?

chb0github commented 12 months ago

My rant: Go insists that maps don't/can't have order. But that's an implementation issue based on the fact that these are Hash based maps instead of Tree based maps (which are ordered).

What might be a slightly better solution than a slice (just a consideration) - take a sort function. Then it can be by insertion order or actual sort order.

I don't know what the spec for mime/multipart says, but definitely don't deviate from it.

jeevatkm commented 11 months ago

@chb0github I hear you! I will have to check the RFC spec for this part.

A possible workaround/approach (as @praem90 mentioned above) is to add a method to accept the slice and process it.

gospider007 commented 10 months ago

I am working with graphql-upload and it's processor must accept one field before any other fields, otherwise it will throw an error. I know that map has no order and should has no order, but if there is anyway to make a raw body of multipart and keep its order?

image

this can help you:

package main

import (
    "log"
    "strings"

    "github.com/gospider007/requests"
)

func main() {
    orderMap := requests.NewOrderMap()
    orderMap.Set("name", "test")
    orderMap.Set("age", 11)
    orderMap.Set("sex", "boy")

    resp, err := requests.Post(nil, "https://httpbin.org/anything", requests.RequestOption{
        Form: orderMap,
    })
    if err != nil {
        log.Panic(err)
    }
    jsonData, err := resp.Json()
    if err != nil {
        log.Panic(err)
    }
    if !strings.HasPrefix(jsonData.Get("headers.Content-Type").String(), "multipart/form-data") {
        log.Panic("json data error")
    }
    if jsonData.Get("form.name").String() != "test" {
        log.Panic("json data error")
    }
}