How to return value from the Looker Golang sdk - go

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
}

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

http: superfluous response.WriteHeader call StatusOK

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)
}

Passing nested JSON as variable in Machinebox GraphQL mutation using golang

Hi there Golang experts,
I am using the Machinebox "github.com/machinebox/graphql" library in golang as client for my GraphQL server.
Mutations with single layer JSON variables work just fine
I am, however, at a loss as to how to pass a nested JSON as a variable
With a single layer JSON I simply create a map[string]string type and pass into the Var method. This in turn populates my graphql $data variable
The machinebox (graphql.Request).Var method takes an empty interface{} as value so the map[string]string works fine. But embedded json simply throws an error.
code:
func Mutate(data map[string]string, mutation string) interface{} {
client := GQLClient()
graphqlRequest := graphql.NewRequest(mutation)
graphqlRequest.Var("data", data)
var graphqlResponse interface{}
if err := client.Run(context.Background(), graphqlRequest, &graphqlResponse); err != nil {
panic(err)
}
return graphqlResponse
}
Mutation:
mutation createWfLog($data: WfLogCreateInput)
{
createWfLog (data: $data){
taskGUID {
id
status
notes
}
event
log
createdBy
}
}
data variable shape:
{
"data": {
"event": "Task Create",
"taskGUID": {
"connect": {"id": "606f46cdbbe767001a3b4707"}
},
"log": "my log and information",
"createdBy": "calvin cheng"
}
}
As mentioned, the embedded json (value of taskGUID) presents the problem. If value was simple string type, it's not an issue.
Have tried using a struct to define every nesting, passed in struct.
Have tried unmarshaling a struct to json. Same error.
Any help appreciated
Calvin
I have figured it out... and it is a case of my noobness with Golang.
I didn't need to do all this conversion of data or any such crazy type conversions. For some reason I got in my head everything HAD to be a map for the machinebox Var(key, value) to work
thanks to xarantolus's referenced site I was able to construct a proper strut. I populated the strut with my variable data (which was a nested json) and the mutation ran perfectly!
thanks!

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:

kubernetes filter objects in Informer

Im writing custom controller for kubernetes.
Im creating shared informer
cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options meta_v1.ListOptions) (k8sruntime.Object, error) {
return client.CoreV1().ConfigMaps(nameSpace).List(options)
},
WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) {
return client.CoreV1().ConfigMaps(nameSpace).Watch(options)
},
},
&api_v1.ConfigMap{},
0, //Skip resyncr
cache.Indexers{},
)
I have option to add filtering function into call back functions to further decrease number of objects im working with.
Something like that
options.FieldSelector := fields.OneTermEqualSelector("metadata.name", nodeName).String()
I would like to filter out objects by regular expression. Or by some label at least. Unfortunately documentation is not helping. Could not find anything except for tests for code itself.
Ho do i apply regular expression on filtering mechanism?
Where do i get some examples on this issue?
Its not possible to filter objects by regular expression.
It is possible to filer object by lable
This is the code that will filter by label
labelSelector := labels.Set(map[string]string{"mylabel": "ourdaomain1"}).AsSelector()
informer := cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options meta_v1.ListOptions) (k8sruntime.Object, error) {
options.LabelSelector = labelSelector.String()
return client.CoreV1().ConfigMaps(nameSpace).List(options)
},
WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) {
options.LabelSelector = labelSelector.String()
return client.CoreV1().ConfigMaps(nameSpace).Watch(options)
},
},
&api_v1.ConfigMap{},
0, //Skip resyncr
cache.Indexers{},
)
Another thing that is important to remember is how do you add new objects to k8s
I was doing something like
kubectl --namespace==ourdomain1 create configmap config4 -f ./config1.yaml
This is not good. It overwrites all the fields in config map and puts whole file content into data of the new object.
Proper way is
kubectl create -f ./config1.yam

Resources