http: superfluous response.WriteHeader call StatusOK - go

In my code, I've a loop that processing set of files (based on what available at pre-specified folder), and based on the output of each processed file, some info is sent to the client, so I wrote the below:
for i, file := range files {
uniqueSlice := unique(matches)
output = Output{MSG: "ok", File: file, Skills: uniqueSlice}
data, err := json.Marshal(output)
if err != nil {
panic(err)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) // -< Error from here
w.Write(data)
}
Above working correctly if the folder has a single file, but if has more than one, I got the error: http: superfluous response.WriteHeader call
I understood the error is due to using w.WriteHeader(http.StatusOK) which can not be used more than once to be set, but I need it to be set for the client to process the returned data.
How can I fix this code, so that I can return data directly to the client upon processing each file.
UPDATE
If I remove http.StatusOK as recommended in the comments below, then I get the returned as plain text not as JSON!

You can't just concatenate JSON documents together and expect the result to be valid json encoded. You'll have to put your output objects in an array and then output that array once at the end, otherwise the response won't be valid json.
If you output objects individually like your code did, the final data will look like
{"MSG": "ok", "File": "...", "Skills": [...]}{"MSG": "ok", "File": "...", "Skills": [...]}{"MSG": "ok", "File": "...", "Skills": [...]}
Each one of those outputs is valid by itself, but the entire output with the objects just concatenated together, is not.
Ideally, when outputting json to a stream like an HTTP response, instead of storing it in an intermediate buffer (data) for you, use json.NewEncoder(w) where w is the http response writer. Streaming is almost always better than rendering to a variable.
var outputs = make([]Output,0,len(files)
for i, file := range files {
uniqueSlice := unique(matches)
outputs = append(outputs, Output{MSG: "ok", File: file, Skills: uniqueSlice})
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(outputs); err != nil {
panic(err)
}

Related

Gmail API - How can I retrieve a thread/message with just the unique id from the gmail address bar?

I'm working on a project, with the gmail api, and I need to read a message in a thread to get some information (like message body and bottom part).
So I'm able to access my inbox, everything is set up and ready to work.
But I struggle with the next step: the only info I have to find my message/thread is the unique id you can find on the gmail url (e.g: https://mail.google.com/mail/u/0/d/xxxxxxx/#inbox/**uniqueID**)
I read the golang documentation for the google gmail api, and I couldn't find any way to get the thread or a message with just this information. Am I wrong?
If not, what could be my solution to this problem?
Scrapping? to retrieve the messageID?
Or is there another library that I could use maybe?
I tried to use the following functions:
`
message, err := srv.Users.Messages.Get(user, uniqueID).Do()
if err != nil {
return fmt.Sprintf("Unable to retrieve message: %v", err)
}
`
and
`
thread, err := srv.Users.Threads.Get(user, uniqueID).Do()
if err != nil {
return fmt.Sprintf("Unable to retrieve thread: %v", err)
}
`
But the uniqueID doesn't work for them, they're expecting the MessageID or ThreadID (IDs that you can find when you click on "Show Original" from a message in Gmail).
Unable to retrieve message: googleapi: Error 400: Invalid id value, invalidArgument
Any suggestion is welcome! ^^
Thanks
If you already have the threadId or the id (MessageID or ThreadID that you get using the method users.messages.list,) your case use the method users.messages.get to get the "Message-ID" under the payload field.
It shows in this format:
{
"name": "Message-ID",
"value": "\u003cMessage-ID\u003e"
},
To get the actual Message-ID (the one under Show original, you will need to trim \u003c at the start of the value, and \u003e at the end.
something like this maybe:
gmailMessageResposne, _ := gmail.Service.Users.Messages.Get("user#email.com", "rfc822msgid").Format("full").Do()
Reference:
Method: users.messages.list
Method: users.messages.get

How to return value from the Looker Golang sdk

I'm attempting to perform the run inline query api endpoint using the Looker Golang SDK. https://github.com/looker-open-source/sdk-codegen/blob/474ee9365dafe6549826a9f627ac0a79dc0e9a56/go/sdk/v4/models.go
https://developers.looker.com/api/explorer/4.0/methods/Query/run_inline_query
However when I execute this I get a blank response back not the expected data from fmt.Println(response). I also attempted to create and run, a sql query, while it looked like the API call executed I didn't receive any results in a very similar fashion. I feel like i'm missing something in getting results. I've validated these queries run in Looker.
Massive disclaimer, I'm a beginner to Golang. I'd really appreciate anyone being able to tell me what i'm doing wrong here.
func getDashboards(sdk *looker.LookerSDK) error {
fields := []string{
"dashboard.id",
"dashboard_element.id",
"dashboard_element.type",
"dashboard_element.result_source",
"query.model",
"query.view",
"query.formatted_fields",
"query.id",
"dashboard.title",
"look.id"}
limit := "5000"
response, err := sdk.RunInlineQuery(
looker.RequestRunInlineQuery{
ResultFormat: "json",
Body: looker.WriteQuery{
Model: "system__activity",
View: "dashboard",
Fields: &fields,
Limit: &limit,
},
}, nil)
if err != nil {
fmt.Println(err)
}
fmt.Println(response)
return err
}

How to bypass the "wildcard route id conflicts with existing children in path" error?

r.GET("/v1.0/:pageId/page", (&page.API{}).Get)
r.POST("/v1.0/:labelId/label", (&label.API{}).Post)
It is a famous problem of gin that this would result in wildcard route id conflicts with existing children in path. However, I am writing this script for returning mock result for testing, so there is absolute need to keep this URL structure. Most solution out there just use 2 wildcard instead and handle the different part in the function it is pointing to. However, as this is using different HTTP method (GET and POST), so it is impossible to use that way to solve the problem. Is there other way to keep this URL structure?
Not sure whether it is the best way.This could work normally:
Use a Group:
v10Group := r.Group("/v1.0/:id", checkTheId)
{
v10Group.GET("/page", func(c *gin.Context) {
c.JSON(200, gin.H{
"msg":"Now you are trying to visit a page",
"id_page": c.Param("id"),
})
})
v10Group.GET("/label", func(c *gin.Context) {
c.JSON(200, gin.H{
"msg":"Now you are trying to visit a label",
"id_label": c.Param("id"),
})
})
}
And a middleware to check the id,Save it in the gin.Context.
func checkTheId(c *gin.Context) {
id := c.Param("id")
b, err := strconv.Atoi(id) // judge whether it is a number
if err != nil{
c.JSON(400,gin.H{
"msg":"Parameter invalid, Please input a number",
})
c.Abort()
return
}
c.Set("id", b)
}
Result:

Go-gin intercepting a request body

I am using go-gin as server and trying to decode the request body. When I send request which has both the strings
{
"name": "abc"
}
The following code decodes it correctly:
var decodedBody map[string]string
err = json.NewDecoder(c.Request.Body).Decode(&decodedBody)
But if I send
{
"id": 1
}
The following code gives me a blank map
var decodedBody map[string]int
err = json.NewDecoder(c.Request.Body).Decode(&decodedBody)
Not sure what am I missing here. Any pointers?
because you set the decodeBody's data type with string,if your value is not the string value, it will not decode the correct value,{"id":1},it's value's type is int,not the string.

Go - How to test with http.NewRequest

I've got below code for testing http request:
func TestAuthenticate(t *testing.T) {
api := &ApiResource{}
ws := new(restful.WebService)
ws.Consumes(restful.MIME_JSON, restful.MIME_XML)
ws.Produces(restful.MIME_JSON, restful.MIME_JSON)
ws.Route(ws.POST("/login").To(api.Authenticate))
restful.Add(ws)
bodyReader := strings.NewReader("<request><Username>42</Username><Password>adasddsa</Password><Channel>M</Channel></request>")
httpRequest, _ := http.NewRequest("POST", "/login", bodyReader)
// httpRequest.Header.Set("Content-Type", restful.MIME_JSON)
httpRequest.Header.Set("Content-Type", restful.MIME_XML)
httpWriter := httptest.NewRecorder()
restful.DefaultContainer.ServeHTTP(httpWriter, httpRequest)
}
I tried to use json as a string with same NewReader and also tried to use struct with json.Marshal.
Neither of them works.
Is there a method where I can code bodyReader for a valid third parameter for http.NewRequest?
Similar request as input for NewReader in JSON is:
bodyReader := strings.NewReader("{'Username': '12124', 'Password': 'testinasg', 'Channel': 'M'}")
Struct fields are is:
Username, Password, Channel
The JSON is invalid. JSON uses " for quoting strings, not '.
Use this line of code to create the request body:
bodyReader := strings.NewReader(`{"Username": "12124", "Password": "testinasg", "Channel": "M"}`)
I used a raw string literal to avoid quoting the " in the JSON text.

Resources