Golang, how to use a struct to write JSON response over HTTP? - http

The Goal:
Using github.com/neelance/graphql-go starwars example, I'm trying to write a JSON response to my ReactJS client. That struct stuff is completely new for me, Golang as well btw.
The question:
What should data variable be in order to get the appropriate response to the following example GraphQL query?
query clientQuery {
character(id: 1000) {
name
appearsIn
}
}
Additional info:
From what I've read here and there, data must be some kind of struct. I've got plenty of structs available in the example (see starwars.go below).
The Code to be modified (main.go):
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/neelance/graphql-go"
"github.com/neelance/graphql-go/example/starwars"
"github.com/neelance/graphql-go/relay"
)
var schema *graphql.Schema
func init() {
schema = graphql.MustParseSchema(starwars.Schema, &starwars.Resolver{})
}
func main() {
port := ":8080"
log.Printf(`GraphQL server starting up on http://localhost%v`, port)
http.Handle("/query", &relay.Handler{Schema: schema})
http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
// THIS IS SUPER WRONG, data should be something
// like data := starwars.Resolver{} or so?
data := `{"data":{"character":{"name":"Luke Skywalker","appearsIn":["NEWHOPE","EMPIRE","JEDI"]}}}`
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(data)
})
log.Fatal(http.ListenAndServe(port, nil))
}
REFERENCE 1 - starwars.go
REFERENCE 2 - relay.go

You question is a bit confusing. You are asking about JSON, but your wanted response is not in a valid JSON format: It looks like you added unrelated GraphQL information.
I am not sure if this is an question about GraphQL or JSON. I will try to answer it anyway.
Your example data looks like this, therefore I assume that is the result you want to generate:
data := `{"data":{"character":{"name":"Luke Skywalker","appearsIn":["NEWHOPE","EMPIRE","JEDI"]}}}`
A clean way to make Go generate a proper JSON is to create Structs which contain the data:
type Response struct {
Data Data `json:"data"`
}
type Data struct {
Character Character `json:"characer"`
}
type Character struct {
Name string `json:"name"`
AppearsIn []string `json:"appearsIn"`
}
Then you can define the data like this:
data := Response{
Data: Data{
Character: Character{
Name: "Luke Skywalker",
AppearsIn: []string{"NEWHOPE", "EMPIRE", "JEDI"},
},
},
}
Perhaps this question isn't about JSON rather than GraphQL. In this case you need to clarify your question.
References
Details about JSON tags (ie json:".."): https://golang.org/pkg/encoding/json/#Marshal
Example with Structs: https://gobyexample.com/structs

Here is a simpler example, which would have helped me if it had been here.
type Password struct {
Password string `json:"password"`
}
func keyHandler(w http.ResponseWriter, r *http.Request) {
response := Password{"password"}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(response)
}

Related

Convert named-type map[string]string to plain one in Golang

I have a map of type set, which is actually a map[string]string. However, passing it to a function which accepts a map[string]string fails, because Go does not recognize set as one.
However, I fail to convince the compiler it is one. Is there any way to resolve this, without looping and copying?
package main
import (
"fmt"
)
type name string
type field string
type set map[name]field // map[string]string after all
type plain map[string]string // also map[string]string
func main() {
var typed = set{"hi": "ho"} // map[string]string?
back := plain(typed) // cannot convert typed (type set) to type plain
back := typed.(plain) // invalid type assertion: typed.(plain) (non-interface type set on left)
echo(back)
}
func echo(in map[string]string) {
fmt.Println(in)
}
You could do this using the unsafe package.
Note: I don't think this would necessarily be a good idea, and probably the right way would be to just iterate and copy, but since it does answer the question asked...
var typed = set{"hi": "ho"} // map[string]string?
p := unsafe.Pointer(&typed)
var back plain
back = *(*plain)(p)
Playground: https://play.golang.org/p/yienSuJSnQU

Get property from reader.io object in golang

I'm new at golang and got some little problem:
I got remoteApi that give me some response when I'm making http request like here:
res, err := http.DefaultClient.Do(req)
the body of the response contains some json such as :
{
a: 'hello'
b: 5
c:[1,2,3]
}
I need to assign the value of "a" to other variable .
What is the best way to access one of res.Body properties? Ive tried to convert to json / string and so but no success
thanks
Something like this should work:
var s struct {
A string
}
err := json.NewDecoder(response.Body).Decode(&s)
// check err
result := s.A
Also please note that your JSON response example is not valid JSON (single quotes instead of double quotes, field names are not quoted, field separators missing) and will not be parsed successfully as such.

Nested values in url.Values

I'm working on an API client and I need to be able to send a nested JSON structure with a client.PostForm request. The issue I'm encountering is this:
reqBody := url.Values{
"method": {"server-method"},
"arguments": {
"download-dir": {"/path/to/downloads/dir"},
"filename": {variableWithURL},
"paused": {"false"},
},
}
When I try to go build this, I get the following errors:
./transmission.go:17: syntax error: unexpected :, expecting }
./transmission.go:24: non-declaration statement outside function body
./transmission.go:26: non-declaration statement outside function body
./transmission.go:27: non-declaration statement outside function body
./transmission.go:29: non-declaration statement outside function body
./transmission.go:38: non-declaration statement outside function body
./transmission.go:39: syntax error: unexpected }
I'm wondering what the correct way to created a nested set of values in this scenario. Thanks in advance!
I was able to figure this out on my own! The answer is to struct all-the-things!
type Command struct {
Method string `json:"method,omitempty"`
Arguments Arguments `json:"arguments,omitempty"`
}
type Arguments struct {
DownloadDir string `json:"download-dir,omitempty"`
Filename string `json:"filename,omitempty"`
Paused bool `json:"paused,omitempty"`
}
Then, when creating your PostForm:
jsonBody, err := json.Marshal(reqBody) // reqBody is a Command
if (err != nil) {
return false
}
req, err := http.NewRequest("POST", c.Url, strings.NewReader(string(jsonBody)))
Hope this helps!
You are not using properly the url.Values, according to the source code (url package, url.go):
// Values maps a string key to a list of values.
// It is typically used for query parameters and form values.
// Unlike in the http.Header map, the keys in a Values map
// are case-sensitive.
type Values map[string][]string
But arguments is not compliant with the definition because the object of arguments is not an array of strings.
I used NewRequest as Connor mentions in his answer but using a struct and then marshalling it seems an unnecessary step to me.
I passed my nested json string straight to strings.NewReader:
import (
"net/http"
"strings"
)
reqBody := strings.NewReader(`{
"method": {"server-method"},
"arguments": {
"download-dir": {"/path/to/downloads/dir"},
"paused": {"false"},
},
}`)
req, err := http.NewRequest("POST", "https://httpbin.org/post", reqBody)
Hope it helps those who are stuck with Go's http PostForm which only accepts url.Values as argument while url.Values cannot generate nested json.

Passing an struct to a Post martini routine

I have an issue using this statement
m.Post(Model, binding.Form(Wish), func(wish Wish, r render.Render, db *mgo.Database) {
This worked fine if I use the struct define inside the prog like
m.Post(Model, binding.Form(Wish1{}) , func(wish Wish1, r render.Render, db *mgo.Database) {
but I need this to be an independent package.
I get "Wish is not a type" wish is the return of the binding function.
This worked with a primary Type struct. I am passing the strut as a interface{}
I am using GO with Martini.Classic() It is really complicated for me to change Martini or Binding package. Any suggestions.
This is the all code
package chlistpkg
import (
"github.com/codegangsta/martini"
"github.com/codegangsta/martini-contrib/binding"
"github.com/codegangsta/martini-contrib/render"
"labix.org/v2/mgo"
"time"
"fmt"
"html/template"
"reflect"
"adminStruct"
)
just to show the struct that I need to pass as to routine Doall
type Wish1 struct {
Name string `form:"name"`
Description string `form:"description"`
AnyDate time.Time `form:"anydate"`
Active bool `form:"active"`
Number int `form:"number"`
NumDec float32 `form:"numDec"`
}
DB Returns a martini.Handler
func DB() martini.Handler {
session, err := mgo.Dial("mongodb://localhost")
if err != nil {
panic(err)
}
return func(c martini.Context) {
s := session.Clone()
c.Map(s.DB("advent2"))
defer s.Close()
c.Next()
}
}
GetAll returns all Wishes in the database
func GetAll(db *mgo.Database, entList interface{}) interface{} {
db.C("wishes").Find(nil).All(entList)
fmt.Println("GettAll entList =", entList)
return entList
}
func Doall(Model string, Wish interface{}, Wish2 interface{}, Wishlist interface{} ) {
m := martini.Classic()
fmt.Println ("martini.Classic =", m)
m.Use(martini.Static("images")) // serve from the "images" directory as well
m.Use(render.Renderer(render.Options{
Directory: "templates",
Layout: "layout",
}))
m.Use(DB())
m.Get(Model, func(r render.Render, db *mgo.Database) {
r.HTML(200, "lista4", GetAll(db, Wishlist))
})
binding does not take a pointer. I have to pass the struct by reference on "Wish"
the issue is the return on "wish Wish" I got an error Wish is not a type
at compilation time
m.Post(Model, binding.Form(Wish), func(wish Wish, r render.Render, db *mgo.Database) {
fmt.Println("Input wish =", wish)
db.C("wishes").Insert(wish)
r.HTML(200, "lista4", GetAll(db, Wishlist))
})
m.Run()
Thanks in advance
Luis
The reason you are getting an error is that you have called your type Wish1 (with a numerical 1) but you are referring to the Wish type (which does not exist!) in your code.
Change your struct to be:
// Note: "Wish", not "Wish1"
type Wish struct {
Name string `form:"name"`
Description string `form:"description"`
AnyDate time.Time `form:"anydate"`
Active bool `form:"active"`
Number int `form:"number"`
NumDec float32 `form:"numDec"`
}
If you want to put your type into another package (tip: don't overdo the sub-packages), then it will need to become a pkgname.Wish as names are fully qualified.
Added
After a second look, you're also messing things up here:
func Doall(Model string, Wish interface{}, Wish2 interface{}, Wishlist interface{} ) {
m := martini.Classic()
fmt.Println ("martini.Classic =", m)
m.Use(martini.Static("images")) // serve from the "images" directory as well
Your parameter list needs to provide a name for each type; you can't pass Wish interface{} as a parameter as Wish is a type, not a variable name.
You should either:
func DoAll(model string, wish interface{}, wish2 interface{}, wishList interface{}) { ... }
Or, better still, stop using interface{} like this and write:
func DoAll(model string, wishList []Wish, wishes... Wish) { ... }
However, your DoAll function does not seem to be referenced elsewhere, and is creating its own Martini instance. I highly suggest thinking about why things are "split out" like this if you're just starting out. Keep it simple - e.g.
func main() {
m := martini.Classic()
m.Use(martini.Static("images"))
m.Use(DB())
m.Use(render.Renderer(render.Options{...}))
// No need for an anonymous function, which just adds clutter
m.Get("/wishes/all", GetAllWishes)
// Same goes for here
m.Post("/wishes/new", PostWish)
m.Run()
}
PS: I've fixed the formatting of your code, as it has a lot of unnecessary spacing before/after parenthesis. Make sure to use gofmt, which is included with the Go install and can be hooked into most popular editors.

Working out the number of times a (request handler) function has been called in Go

Context
I'm making a web app that serves dynamically generated pdfs. These contain content from the internet, so every time it serves a pdf, it downloads a number of files to a new temporary folder.
The Problem
I end up with a large number of folders after I load the page once, so it seems that, for some reason, the handler is being called multiple times, which is an issue because I'm downloading multiple times more than I need to of not insubstantial files. I'd like to check at what stage of the process multiple requests are occurring.
The Question
Is there a way of working out how many times a function has been called, quite possibly using closures? (I haven't quite got closures into my mental model for programming yet; I don't completely understand them/how they're used).
This would preferably be something involving an int in the language rather than printing something at every stage and counting by hand - I'm looking for a more scalable solution than that (for later situations as well as this one).
Thanks!
Here are two ways you can count function calls, and one for method calls. There are plenty of other ways too, but just to get you started:
Using closure: (not what I would recommended)
package main
import(
"fmt"
"sync/atomic"
)
var Foo = func() (func() uint64) {
var called uint64
return func() uint64 {
atomic.AddUint64(&called, 1)
fmt.Println("Foo!")
return called
}
}()
func main() {
Foo()
c := Foo()
fmt.Printf("Foo() is called %d times\n", c)
}
Playground: http://play.golang.org/p/euKbamdI7h
Using global counter:
package main
import (
"fmt"
"sync/atomic"
)
var called uint64
func Foo() {
atomic.AddUint64(&called, 1)
fmt.Println("Foo!");
}
func main() {
Foo()
Foo()
fmt.Printf("Foo() is called %d times\n", called)
}
Playground: http://play.golang.org/p/3Ib29VCnoF
Counting method calls:
package main
import (
"fmt"
"sync/atomic"
)
type T struct {
Called uint64
}
func (t *T) Foo() {
atomic.AddUint64(&t.Called, 1)
fmt.Println("Foo!")
}
func main() {
var obj T
obj.Foo()
obj.Foo()
fmt.Printf("obj.Foo() is called %d times\n", obj.Called)
}
Playground: http://play.golang.org/p/59eOQdUQU1
Edit:
I just realized that the handler might not be in your own package. In such a case, you might want to write a wrapper:
var called uint64
func Foo() {
atomic.AddUint64(&called, 1)
importedPackage.Foo()
}
Edit 2:
Updated the examples to use atomic +1 operations.
Counting Calls
To answer the specific question you asked, here is one quick way to count handler executions:
func countCalls(h http.HandlerFunc) http.HandlerFunc {
var lock sync.Mutex
var count int
return func(w http.ResponseWriter, r *http.Request) {
lock.Lock()
count++
w.Header().Set("X-Call-Count", fmt.Sprintf("%d", count))
lock.Unlock()
h.ServeHTTP(w, r)
}
}
http.Handle("/foobar", countCalls(foobarHandler))
This will add a header that you can inspect with your favorite web developer tools; you could also just log it to standard output or something.
Logging Handlers
To expand upon the answers mentioned above, what you probably want to do to debug this and have in place for future use is to log details of each request.
package main
import (
"flag"
"log"
"net/http"
"os"
"github.com/gorilla/handlers"
)
var (
accessLogFile = flag.String("log", "/var/log/yourapp/access.log", "Access log file")
)
func main() {
accessLog, err := os.OpenFile(*accessLogFile, os.O_CREATE|os.O_WRITE|os.O_APPEND, 0644)
if err != nil {
log.Fatalf("Failed to open access log: %s", err)
}
wrap := func(f http.HandlerFunc) http.Handler {
return handlers.LoggingHandler(accessLog, http.HandlerFunc(foobarHandler))
}
http.Handle("/foobar", wrap(foobarHandler))
...
}
This uses LoggingHandler (or CombinedLoggingHandler) to write a standard Apache format log message that you can either inspect yourself or analyze with various tools.
An example of a log line would be
127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
which tells you who made the request, when, what the method and URL was, how your server responded, and how long the response was. From this log, you should be able to see exactly what requests are being made, to determine not only how many times your handlers are being called, but exactly what is generating the requests and whether they're to another endpoint (like /favicon.ico).

Resources