如何在Golang中编写用于YouTrack REST API的curl请求?

huangapple go评论76阅读模式
英文:

How to write such curl request in golang for youtrack rest api?

问题

我正在使用YouTrack REST编写Golang客户端。我已经编写了大部分API的路径,但在将文件附加到问题时遇到了问题。所以,这里有一个小而好的文档https://www.jetbrains.com/help/youtrack/devportal/api-usecase-attach-files.html

使用这个文档和其他文档页面中的命令在curl(通过终端)中可以工作。我是Golang的新手,但必须使用这种语言编写。

func createForm(form map[string]string) (string, io.Reader, error) {
	body := new(bytes.Buffer)
	mp := multipart.NewWriter(body)
	defer mp.Close()
	for key, val := range form {
		if strings.HasPrefix(val, "@") {
			val = val[1:]
			file, err := os.Open(val)
			if err != nil {
				return "", nil, err
			}
			defer file.Close()
			part, err := mp.CreateFormFile(key, val)
			if err != nil {
				return "", nil, err
			}
			io.Copy(part, file)
		} else {
			mp.WriteField(key, val)
		}
	}
	return mp.FormDataContentType(), body, nil
}

func AttachFileToIssue(path string, issueID string) {
	form := map[string]string{"image": "@image.jpeg", "key": "KEY"}
	_, body, err := createForm(form)
	if err != nil {
		panic(err)
	}

	req, err := http.NewRequest("POST", youTrackUrl+"/api/issues/"+issueID+"/attachments?fields=id,name", body)

	if err != nil {
		// handle err
	}
	req.Header.Set("Authorization", "Bearer "+youTrackToken)
	req.Header.Set("Content-Type", "multipart/form-data")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		// handle err
	}
	fmt.Println(resp)
	if resp.StatusCode == http.StatusOK {
		bodyBytes, err := io.ReadAll(resp.Body)
		if err != nil {
			log.Fatal(err)
		}
		bodyString := string(bodyBytes)
		fmt.Println(bodyString)
	}
	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {

		}
	}(resp.Body)
}

错误代码是:

{400 Bad Request 400 HTTP/1.1 1 1 map[Access-Control-Expose-Headers:[Location] Cache-Control:[no-cache, no-store, no-transform, must-revalidate] Content-Length:[110] Content-Type:[application/json;charset=utf-8] Date:[Sun, 10 Jul 2022 10:28:24 GMT] Referrer-Policy:[same-origin] Server:[YouTrack] X-Content-Type-Options:[nosniff] X-Frame-Options:[SAMEORIGIN] X-Xss-Protection:[1; mode=block]] 0xc0001cc100 110 [] false false map[] 0xc000254000 <nil>}

我使用Wireshark检查了问题所在,问题出在mime-part上,有些东西丢失了。

curl请求:

curl -v -i -F upload=@/Users/jetbrains/Downloads/youtrack.txt \
-F upload=@/Users/jetbrains/Downloads/youtrack_new.jpeg \
-H 'Authorization: Bearer perm:cm9vdA==.MjZGZWI=.WB02vjX0cM2ltLTJXUE3VOWHpJYYNx' \
-H 'Content-Type: multipart/form-data' \
-X POST 'https://example.youtrack.cloud/api/issues/99-500/attachments?fields=id,name'
英文:

I am writing golang client with youtrack REST
I have written the most most path of API. But faced problem with attaching files to an Issue.
So, here there is small and good doc https://www.jetbrains.com/help/youtrack/devportal/api-usecase-attach-files.html

The using the commands from this and other doc pages are worked with curl(via terminal)
I am newby in golang, but have to write in this language.

func createForm(form map[string]string) (string, io.Reader, error) {
body := new(bytes.Buffer)
mp := multipart.NewWriter(body)
defer mp.Close()
for key, val := range form {
if strings.HasPrefix(val, &quot;@&quot;) {
val = val[1:]
file, err := os.Open(val)
if err != nil {
return &quot;&quot;, nil, err
}
defer file.Close()
part, err := mp.CreateFormFile(key, val)
if err != nil {
return &quot;&quot;, nil, err
}
io.Copy(part, file)
} else {
mp.WriteField(key, val)
}
}
return mp.FormDataContentType(), body, nil
}
func AttachFileToIssue(path string, issueID string) {
form := map[string]string{&quot;image&quot;: &quot;@image.jpeg&quot;, &quot;key&quot;: &quot;KEY&quot;}
_, body, err := createForm(form)
if err != nil {
panic(err)
}
req, err := http.NewRequest(&quot;POST&quot;, youTrackUrl+&quot;/api/issues/&quot;+issueID+&quot;/attachments?fields=id,name&quot;, body)
if err != nil {
// handle err
}
req.Header.Set(&quot;Authorization&quot;, &quot;Bearer &quot;+youTrackToken)
req.Header.Set(&quot;Content-Type&quot;, &quot;multipart/form-data&quot;)
resp, err := http.DefaultClient.Do(req)
if err != nil {
// handle err
}
fmt.Println(resp)
if resp.StatusCode == http.StatusOK {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
bodyString := string(bodyBytes)
fmt.Println(bodyString)
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
}
}(resp.Body)
}

The error code is:

{400 Bad Request 400 HTTP/1.1 1 1 map[Access-Control-Expose-Headers:[Location] Cache-Control:[no-cache, no-store, no-transform, must-revalidate] Content-Length:[110] Content-Type:[application/json;charset=utf-8] Date:[Sun, 10 Jul 2022 10:28:24 GMT] Referrer-Policy:[same-origin] Server:[YouTrack] X-Content-Type-Options:[nosniff] X-Frame-Options:[SAMEORIGIN] X-Xss-Protection:[1; mode=block]] 0xc0001cc100 110 [] false false map[] 0xc000254000 &lt;nil&gt;}

I used wireshark to check what is wrong, the problem is with mime-part, something missing.

The curl REQUEST:

curl -v -i -F upload=@/Users/jetbrains/Downloads/youtrack.txt \
-F upload=@/Users/jetbrains/Downloads/youtrack_new.jpeg \
-H &#39;Authorization: Bearer perm:cm9vdA==.MjZGZWI=.WB02vjX0cM2ltLTJXUE3VOWHpJYYNx&#39; \
-H &#39;Content-Type: multipart/form-data&#39; \
-X POST &#39;https://example.youtrack.cloud/api/issues/99-500/attachments?fields=id,name&#39;

答案1

得分: 0

Ana Bartasheva是正确的!

解决方案:

func createForm(form map[string]string) (string, io.Reader, error) {
	body := new(bytes.Buffer)
	mp := multipart.NewWriter(body)
	defer func(mp *multipart.Writer) {
		err := mp.Close()
		if err != nil {

		}
	}(mp)
	var file *os.File
	for key, val := range form {
		if strings.HasPrefix(val, "@") {
			val = val[1:]
			file, err := os.Open(val)
			if err != nil {
				return "", nil, err
			}
			part, err := mp.CreateFormFile(key, val)
			if err != nil {
				return "", nil, err
			}
			_, err = io.Copy(part, file)
			if err != nil {
				return "", nil, err
			}
		} else {
			err := mp.WriteField(key, val)
			if err != nil {
				return "", nil, err
			}
		}
	}
	defer func(file *os.File) {
		err := file.Close()
		if err != nil {

		}
	}(file)

	return mp.FormDataContentType(), body, nil
}

func AttachFileToIssue(path string, issueID string) string {
	form := map[string]string{"path": "@" + path}
	mp, body, err := createForm(form)
	if err != nil {
		panic(err)
	}
	req, err := http.NewRequest("POST", youTrackUrl+"/api/issues/"+issueID+"/attachments?fields=id,name", body)

	if err != nil {
		// handle err
	}

	req.Header.Set("Authorization", "Bearer "+youTrackToken)
	req.Header.Set("Content-Type", mp)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		// handle err
	}
	if resp.StatusCode == http.StatusOK {
		bodyBytes, err := io.ReadAll(resp.Body)
		if err != nil {
			log.Fatal(err)
		}
		bodyString := string(bodyBytes)
		return bodyString
	}
	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {

		}
	}(resp.Body)
	return ""
}

以上是给问题中的代码进行的翻译。

英文:

Ana Bartasheva is right!

The solution:

func createForm(form map[string]string) (string, io.Reader, error) {
body := new(bytes.Buffer)
mp := multipart.NewWriter(body)
defer func(mp *multipart.Writer) {
err := mp.Close()
if err != nil {
}
}(mp)
var file *os.File
for key, val := range form {
if strings.HasPrefix(val, &quot;@&quot;) {
val = val[1:]
file, err := os.Open(val)
if err != nil {
return &quot;&quot;, nil, err
}
part, err := mp.CreateFormFile(key, val)
if err != nil {
return &quot;&quot;, nil, err
}
_, err = io.Copy(part, file)
if err != nil {
return &quot;&quot;, nil, err
}
} else {
err := mp.WriteField(key, val)
if err != nil {
return &quot;&quot;, nil, err
}
}
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
}
}(file)
return mp.FormDataContentType(), body, nil
}
func AttachFileToIssue(path string, issueID string) string {
form := map[string]string{&quot;path&quot;: &quot;@&quot; + path}
mp, body, err := createForm(form)
if err != nil {
panic(err)
}
req, err := http.NewRequest(&quot;POST&quot;, youTrackUrl+&quot;/api/issues/&quot;+issueID+&quot;/attachments?fields=id,name&quot;, body)
if err != nil {
// handle err
}
req.Header.Set(&quot;Authorization&quot;, &quot;Bearer &quot;+youTrackToken)
req.Header.Set(&quot;Content-Type&quot;, mp)
resp, err := http.DefaultClient.Do(req)
if err != nil {
// handle err
}
if resp.StatusCode == http.StatusOK {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
bodyString := string(bodyBytes)
return bodyString
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
}
}(resp.Body)
return &quot;&quot;
}

huangapple
  • 本文由 发表于 2022年7月12日 00:47:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/72941957.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定