Reputation: 319
I want to convert below code to golang.
curl -X POST
'https://api.documo.com/v1/fax/send' \
-H 'Authorization: Basic YOUR_API_KEY' \
-H 'content-type: multipart/form-data' \
-F 'recipientFax=12345678900' \
-F 'coverPage=false' \
-F 'recipientName=John' \
-F 'subject=test' \
-F 'notes=test' \
-F '=@/home/user/Documents/Sample.pdf'
Please help
Below is my code what i have tried.
func SendFaxDocumo(files []*multipart.FileHeader, params map[string]string) {
request, err := SendMultipartRequest("https://api.documo.com/v1/fax/send", params, files)
if err != nil {
fmt.Println(err.Error())
}
client := &http.Client{}
resp, err := client.Do(request)
if err != nil {
fmt.Println(err.Error())
} else {
body := &bytes.Buffer{}
_, err := body.ReadFrom(resp.Body)
if err != nil {
fmt.Println(err.Error())
}
resp.Body.Close()
fmt.Println(resp.StatusCode)
fmt.Println(resp.Header)
fmt.Println(body)
}
}
func SendMultipartRequest(uri string, params map[string]string, files []*multipart.FileHeader) (*http.Request, error) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
for i, _ := range files {
// string_index := strconv.Itoa(i)
file, err := files[i].Open()
defer file.Close()
if err != nil {
fmt.Println(err)
}
doc , err := ioutil.ReadAll(file)
if err != nil {
fmt.Println(err,980)
}
part, err := writer.CreateFormFile("file",files[i].Filename)
if err != nil {
fmt.Println(err)
}
part.Write([]byte(string(doc)))
if _, err = io.Copy(part, file); err != nil {
fmt.Println(err)
}
if err != nil {
fmt.Println(err)
}
}
for key, val := range params {
_ = writer.WriteField(key, val)
}
err := writer.Close()
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", uri, body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", "Basic my_key")
return req, err
}
And the error i am getting is below: {"error":{"name":"Error","message":"File extension not allowed. Allowed formats: tiff,gif,png,jpeg,pdf,doc,xls,ppt,pcl,eps,ps,txt,rtf,xml,fxc,docx,pptx,xlsx"}}
This is the response got from the url requested even if i am trying it by pdf.
Upvotes: 1
Views: 1948
Reputation: 11
I just spent a long few days researching the same problem. After using httputil.DumpRequest
to view what data I was actually passing to Documo, I saw that the content-type header for the file field was set to Content-Type: application/octet-stream
. This is set by the CreateFormFile
method you're using. See the multipart pkg for the source code.
The octet-stream
subtype is used as a default for binary files or files that need to be opened in an application. See MDN, IANA, or this awesome explanation.
The problem, as far as I understand it, is that Documo expects us to explicitly tell them what type of file we're sending them so they know how to handle the rendering. So for my case, octet-stream
didn't tell them anything. Switching the file content-type to application/pdf
did the trick.
Instead of calling writer.CreateFormField
, I basically copied the three lines from the source code of CreateFormFile
and hard coded the Content-Type
to header to application/pdf
instead of application/octet-stream
(Note: my service only deals with PDF right now, so you may need to adjust this if your files are different types).
Code:
func SendMultipartRequest(uri string, params map[string]string, files []*multipart.FileHeader) (*http.Request, error) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
for i, _ := range files {
file, err := files[i].Open()
defer file.Close()
if err != nil {
fmt.Println(err)
}
//////////////////////////////////////////////////////
// replace create CreateFormFile with this
h := make(textproto.MIMEHeader) // import "net/textproto"
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, files[i].Filename)
h.Set("Content-Type", "application/pdf") // this is where you'll set your document type(s)
fileWriter, err := form.CreatePart(h)
///////////////////////////////////////////////////////
if err != nil {
fmt.Println(err)
}
if _, err = io.Copy(fileWriter, file); err != nil {
fmt.Println(err)
}
if err != nil {
fmt.Println(err)
}
}
for key, val := range params {
_ = writer.WriteField(key, val)
}
err := writer.Close()
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", uri, body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", "Basic my_key")
return req, err
}
It's not the sexiest solution but I'm finally able to send complete documents through Documo now.
Hope this helps.
Upvotes: 1