How can I resolve 400 status code by sending POST in Golang? - go

I have Python script, that works fine
def register():
url = prime_url + '/v2/mobile/user/register?lang=ru'
payload = {
'email' : 'test#test.test.mail.com',
'deviceId' : 'testId',
'password' : 'Test1234'
}
response = requests.post(url, data = payload)
print(response.text)
Response:
{"success":true,"data":"SUCCESS_FIRST_STAGE_REGISTER","params":"Two-factor authentication code sent to test#testtest.test.mail.com","code":200,"runTime":2.391624927520752}
I wrote code on Golang:
func postRequest(target string, params string) {
var jsonStr = []byte(`{"email":"testtestetetsees#mail.ru", "deviceId":"ftefst891", "password":"qwertyQwerty132"}`)
req, err := http.NewRequest("POST", target, bytes.NewBuffer(jsonStr))
if err != nil {
log.Fatalln(err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(result)
}
Response:
map[code:400 data:ERROR_VALIDATE params:map[deviceId:[Device Id cannot be blank.] email:[Email cannot be blank.] password:[Password cannot be blank.]] runTime:0.023465871810913086 success:false]
I see that problem is by sending JSON string. What should I do?

As mentioned by Peter in the comments you can use PostForm once you convert the data into url.Values.
If the server expects content in urlencoded form but the input you have is json you'll have to convert it first.
var data = []byte(`{"email":"testtestetetsees#mail.ru", "deviceId":"ftefst891", "password":"qwertyQwerty132"}`)
m := map[string]string{}
if err := json.Unmarshal(data, &m); err != nil {
panic(err)
}
v := url.Values{}
for key, val := range m {
v.Add(key, val)
}
resp, err := http.PostForm("https://example.com", v)
if err != nil {
panic(err)
}
// ...
If the input you have is already in urlencoded form but it needs escaping you can parse it using url.ParseQuery and let the result of that do the escaping.
var data = "email=testtestetetsees#mail.ru&deviceId=ftefst891&password=qwertyQwerty132"
v, err := url.ParseQuery(data)
if err != nil {
panic(err)
}
resp, err := http.PostForm("https://example.com", v)
if err != nil {
panic(err)
}
// ...

Mention content type as "application/json"
For simplicity you can use http.Post, use the below code as a example:
resp, err := http.Post(target, "application/json", bytes.NewBuffer([]byte("{\"email\":\"testtestetetsees#mail.ru\", \"deviceId\":\"ftefst891\", \"password\":\"qwertyQwerty132\"}")))

Related

Send base64 Image to RestApi As A Image (MultiPart)

Assume that I have a base64 image png or jpeg format and I want to send this data to another api.
My Code is :
data2 := data_base64[strings.IndexByte(data_base64, ',')+1:]
reader2 := base64.NewDecoder(base64.StdEncoding, strings.NewReader(data2))
buff2 := bytes.Buffer{}
_, err2 := buff2.ReadFrom(reader2)
if err2 != nil {
fmt.Println(err2.Error())
fmt.Println("Empyt Buffer")
return "0"
}else{
fmt.Println("No Problem")
}
url := "blabla.com"
method := "POST"
payload := &bytes.Buffer{}
writer := multipart.NewWriter(payload)
/*file, errFile1 := os.Open("/Users/xxx/Desktop/test.png")
defer file.Close()*/
part1,
errFile1 := writer.CreateFormFile("image","test.png")
_, errFile1 = io.Copy(part1, reader2)
if errFile1 != nil {
fmt.Println(errFile1)
return "0"
}
err := writer.Close()
if err != nil {
fmt.Println(err)
return "0"
}
client := &http.Client {
}
req, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
return "0"
}
req.Header.Set("Content-Type", writer.FormDataContentType())
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return "0"
}
defer res.Body.Close()
But with this code I got a 500 error response.
If I changhe this
_, errFile1 = io.Copy(part1, reader2)
To this
_, errFile1 = io.Copy(part1, file)
There is no problem.
How can send base64 data to send api like file?
Delete this code and works.
buff2 := bytes.Buffer{}
_, err2 := buff2.ReadFrom(reader2)
if err2 != nil {
fmt.Println(err2.Error())
fmt.Println("Empyt Buffer")
return "0"
}else{
fmt.Println("No Problem")
}
Thanks Leaf Bebop

Golang API Post upload file

I'm new to golang and I'm trying to write a function that uploads a file with a post request to API server. I try Post API in Postman, it is OK but in my code I have some error like this image
This is my golang code:
func (c *Client) PostUploadFile(endpoint string, params map[string]string) []byte {
url := "/examples/image/text.txt"
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// Open the file
file, err := os.Open(url)
if err != nil {
// return nil, err
}
// Close the file later
defer file.Close()
part, err := writer.CreateFormFile("file", filepath.Base(url))
_, err = io.Copy(part, file)
if err != nil {
fmt.Println(err)
// return nil, err
}
for key, val := range params {
_ = writer.WriteField(key, val)
}
err = writer.Close()
if err != nil {
// return nil, err
}
fmt.Println("Data request:")
fmt.Println(body)
fmt.Println("Endpoint:")
fmt.Println(c.BaseUrl + endpoint)
req, requestErr := http.NewRequest("POST", c.BaseUrl+endpoint, body)
if requestErr != nil {
log.Fatalln(requestErr)
}
req.Header.Add("auth_token", c.AuthToken)
req.Header.Add("accept", "application/json")
// req.Header.Add("Content-Type", "application/json")
req.Header.Add("Content-Type", writer.FormDataContentType())
client := &http.Client{}
fmt.Println("Response:")
resp, err := client.Do(req)
fmt.Println(resp)
if err != nil {
log.Println(err)
return []byte(``)
}
return c.parseBody(resp)
}
and this is a param formdata in body:
fmt.Printf("%+v\n", c.UploadImage(map[string]string{
"file": "/examples/image/text.txt",
"wfs_id": "30578",
"id": "59284",
"element_id": "119726",
}))

How do I send an http post request with image and with some parameters in Go?

I am trying to make an http post request with image and parameters in the form-data, but when I am adding image, my parameters are lost.
testProduct := &Product{
Name: "TestProductName",
ImageExtension: "png",
}
var b bytes.Buffer
multipartWriter := multipart.NewWriter(&b)
multipartWriter.CreateFormFile("image", "../test.png")
multipartWriter.Close()
form = url.Values{}
form.Add("name", testProduct.Name)
form.Add("image_extension", testProduct.ImageExtension)
req, _ := http.NewRequest(http.MethodPost, "api/v1/admin/products/", &b)
req.PostForm = form
req.Header.Add("Authorization", "Bearer "+loginResponse.Token)
req.Header.Set("Content-Type", multipartWriter.FormDataContentType())
recorder := httptest.NewRecorder()
router.ServeHTTP(recorder, req)
But when the request handled the parameters doesn't bind:
https://i.imgur.com/JmT4qLh.png
This is the product struct:
type Product struct {
ID string `form:"id" json:"id"`
Name string `form:"name" json:"name"`
Price int64 `form:"price" json:"price"`
ImageExtension string `form:"image_extension" json:"image_extension"`
}
testProduct := &Product{
Name: "TestProductName",
ImageExtension: "png",
}
pr, pw := io.Pipe()
form := multipart.NewWriter(pw)
go func() {
defer pw.Close()
err := form.WriteField("name", testProduct.Name)
if err != nil {
return
}
err = form.WriteField("image_extension", testProduct.ImageExtension)
file, err := os.Open("a.png") // path to image file
if err != nil {
return
}
w, err := form.CreateFormFile("image", "sampleImageFileName.png")
if err != nil {
return
}
_, err = io.Copy(w, file)
if err != nil {
return
}
form.Close()
}()
r, err := http.NewRequest(http.MethodPost, "api/v1/admin/products/", pr)
if err != nil {
return
}
r.Header.Set("Content-Type", form.FormDataContentType())

How to get response with JWT in Golang

I'm trying get the response from an API that uses JSON Web token, I need use the header : {
Authorization: "Bearer token"
}
But I would like to keep the timeout of the http.Client that I'm using. How could I do it?
var myClient = &http.Client{Timeout: 10 * time.Second}
func getJson(url string, target interface{}) error {
r, err := myClient.Get(url)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
net/http.Request has a Header field that you can directly edit, but this means you can't use the shortcut client.Get method. Something more like:
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return err
}
req.Header = map[string][]string{
"Authorization": {fmt.Sprintf("Bearer %s", jwt)},
}
r, err := myClient.Do(req)
...
You could do something like this,
func getJson(url string, target interface{}) error {
req, err := http.NewRequest(http.MethodGet, url, nil)
if nil != err {
return err
}
r, err := myClient.Do(req)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
Alternatively , you could also use context to control the request timeout
func getJsonWithContext(url string, target interface{}) error {
req, err := http.NewRequest(http.MethodGet, url, nil)
if nil != err {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*1)
defer cancel()
reqWithContext := req.WithContext(ctx)
r, err := myClient.Do(reqWithContext)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}

Go lang RPC return EOF error

I'm using http to call RPC with code below
func (c *CallClient) Wallet(method string, req, rep interface{}) error {
client := &http.Client{}
data, _ := EncodeClientRequest(method, req)
reqest, _ := http.NewRequest("POST", c.endpoint, bytes.NewBuffer(data))
resp, err := client.Do(reqest)
if err != nil {
return err
}
defer resp.Body.Close()
io.Copy(ioutil.Discard, resp.Body)
return DecodeClientResponse(resp.Body, rep)
}
with EncodeClientRquest && DecodeClientResponse
// EncodeClientRequest encodes parameters for a JSON-RPC client request.
func EncodeClientRequest(method string, args interface{}) ([]byte, error) {
c := &clientRequest{
Version: "2.0",
Method: method,
Params: [1]interface{}{args},
Id: uint64(rand.Int63()),
}
return json.Marshal(c)
}
// DecodeClientResponse decodes the response body of a client request into
// the interface reply.
func DecodeClientResponse(r io.Reader, reply interface{}) error {
var c clientResponse
if err := json.NewDecoder(r).Decode(&c); err != nil {
return err
}
if c.Error != nil {
return fmt.Errorf("%v", c.Error)
}
if c.Result == nil {
return errors.New("result is null")
}
return json.Unmarshal(*c.Result, reply)
}
And I got error EOF.
This line:
io.Copy(ioutil.Discard, resp.Body)
reads the whole resp.Body, leaving the reader with no more bytes to be read. Therefore any successive calls to resp.Body.Read will return EOF and the json.Decoder.Decode method does use the io.Reader.Read method when decoding the given reader's content, so...
And since resp.Body is an io.ReadCloser, which is an interface that does not support "rewinding", and you want to read the body content more than once (ioutil.Discard and json.Decode), you'll have to read the body into a variable that you can re-read afterwards. It's up to you how you do that, a slice of bytes, or bytes.Reader, or something else.
Example using bytes.Reader:
func (c *CallClient) Wallet(method string, req, rep interface{}) error {
client := &http.Client{}
data, err := EncodeClientRequest(method, req)
if err != nil {
return err
}
reqest, err := http.NewRequest("POST", c.endpoint, bytes.NewBuffer(data))
if err != nil {
return err
}
resp, err := client.Do(reqest)
if err != nil {
return err
}
defer resp.Body.Close()
// get a reader that can be "rewound"
buf := bytes.NewBuffer(nil)
if _, err := io.Copy(buf, resp.Body); err != nil {
return err
}
br := bytes.NewReader(buf.Bytes())
if _, err := io.Copy(ioutil.Discard, br); err != nil {
return err
}
// rewind
if _, err := br.Seek(0, 0); err != nil {
return err
}
return DecodeClientResponse(br, rep)
}

Resources