These are AppHandlers from a pattern I found online while researching gorilla/mux. They part of a struct that satisfies http.Handler. If you notice, the following two blocks are exactly the same. Effectively, they could be passed the 'variant' ("flow" or "process") as a string.
func CreateFlow(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {
highest, code, err := a.Create("flow", r)
if code != 200 || err != nil {
return code, err
}
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(struct {
Highest int `json:"id"`
}{highest})
w.Header().Set("Content-Type", "application/json")
w.Write(b.Bytes())
return 200, nil
}
func CreateProcess(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {
highest, code, err := a.Create("process", r)
if code != 200 || err != nil {
return code, err
}
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(struct {
Highest int `json:"id"`
}{highest})
w.Header().Set("Content-Type", "application/json")
w.Write(b.Bytes())
return 200, nil
}
However, the following two blocks not only need the string, but they need a variable of the associated type ("Flow" and "Process") to successfully Unmarshal the hit I get from ElasticSearch. Other than that, they are Identical code.
func GetFlow(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {
hit, code, err := a.GetByID("flow", mux.Vars(r)["id"], r)
if code != 200 {
return code, err
}
var flow Flow
err = json.Unmarshal(*hit.Source, &flow)
if err != nil {
return 500, err
}
flow.ESID = hit.Id
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(flow)
w.Header().Set("Content-Type", "application/json")
w.Write(b.Bytes())
return 200, nil
}
func GetProcess(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {
hit, code, err := a.GetByID("process", mux.Vars(r)["id"], r)
if code != 200 {
return code, err
}
var process Process
err = json.Unmarshal(*hit.Source, &process)
if err != nil {
return 500, err
}
process.ESID = hit.Id
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(process)
w.Header().Set("Content-Type", "application/json")
w.Write(b.Bytes())
return 200, nil
}
I am not sure how to generalize this behavior in golang when there is a declared type involved. These handlers are all in the same package too, as I think that they are all accomplishing a similar task. I am very clearly repeating myself in code but I need advice on how I can improve. I've gone past "a little copying is better than a little dependency." but I am afraid because "reflection is never clear".
Here is an example of the declaration in main using one of these functions.
api.Handle("/flow/{id:[0-9]+}", handlers.AppHandler{context, handlers.GetFlow}).Methods("GET")
You can do it by passing in an exemplar of the necessary type, the same way that Unmarshal does it:
func GetFlow(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {
return GetThing(a,w,r,"flow",new(Flow))
}
func GetProcess(a *AppContext, w http.ResponseWriter, r *http.Request) (int, error) {
return GetThing(a,w,r,"process",new(Process))
}
func GetThing(a *AppContext, w http.ResponseWriter, r *http.Request, t string, ob Elastible{}) (int, error) {
hit, code, err := a.GetByID(t, mux.Vars(r)["id"], r)
if code != 200 {
return code, err
}
err = json.Unmarshal(*hit.Source, ob)
if err != nil {
return 500, err
}
ob.SetESID(hit.Id)
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(ob)
w.Header().Set("Content-Type", "application/json")
w.Write(b.Bytes())
return 200, nil
}
type Elastible interface {
SetESID(id ESIDType) // whatever type ESID is, not clear from example
}
func (f *Flow) SetESID(id ESIDType) {
f.ESID = id
}
This code is untested (because I don't have your struct defs or other dependent code) but I hope it gets the idea across.
Alright, I propose a solution that will give you the maximum code reuse and minimum code copying. This, in my opinion, is by far the most generic solution. We will also take into account the answer given by https://stackoverflow.com/users/7426/adrian to complete the solution. You only have to define a single function which will be a higher order function CreateHandler which will return a function of the following signature:
func(*AppContext, http.ResponseWriter, http.Request) (int, error).
This signature is the actual signature of the handler that is to be used as a mux end point. The solution involves defining a Handler type which is a struct having three fields:
• handlerType: Think of it as an enum having either a value of "CREATE" or "GET". This will decide which among the two blocks of code that you pasted in your question should we use.
• handlerActionName: This will tell the "CREATE" or "GET" which Elastible to use. Value should either be "flow" or "process".
• elastible: This will the Interface type Elastible that will have the SetESID function. We will use this to send our Flow or Process types to our Handler. Thus both Flow and Process should satisfy our interface.
This will make the solution even more generic and will only calling handler.elastible.SetESID() and we will have inserted the ESID irrespective of that fact the underlying type in 'elastible' can either be 'Flow' or a 'Process'
I also define a sendResponse(response interface{}) function that we will resuse to send the response. It acquires w http.ResponseWriter using closure. response can thus be anything, a
struct {
Highest int `json:"id"`
}{highest}
or a Flow or a Process. This will make this function generic too.
The complete solution would now be.
// This is the type that will be used to build our handlers.
type Handler struct {
handlerType string // Can be "CREATE" or "GET"
handlerActionName string // Can be "flow" or "process"
elastible Elastible // Can be *Flow or *Process
}
// Your ESID Type.
type ESIDType string
// Solution proposed by https://stackoverflow.com/users/7426/adrian.
type Elastible interface {
SetESID(id ESIDType)
}
// Make the Flow and Process pointers implement the Elastible interface.
func (flow *Flow) SetESID(id ESIDType) {
flow.ESID = id
}
func (process *Process) SetESID(id ESIDType) {
process.ESID = id
}
// Create a Higher Order Function which will return the actual handler.
func CreateHandler(handler Handler) func(*AppContext, http.ResponseWriter, http.Request) (int, error) {
return func(a *AppContext, w http.ResponseWriter, r http.Request) (int, error) {
// Define a sendResponse function so that we may not need to copy paste it later.
// It captures w using closure and takes an interface argument that we use to call .Encode() with.
sendResponse := func(response interface{}) (int, error) {
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(response)
w.Header().Set("Content-Type", "application/json")
w.Write(b.Bytes())
return 200, nil
}
// Define these variables beforehand since we'll be using them
// in both the if and else block. Not necessary really.
var code int
var err error
// Check the handlerType. Is it create or get?
if handler.handlerType == "CREATE" {
var highest int
// Creates the thing using handler.handlerActionName which may be "flow" or "process"
highest, code, err = a.Create(handler.handlerActionName, r)
if code != 200 || err != nil {
return code, err
}
// Send the response using the above defined function and return.
return sendResponse(struct {
Highest int `json:"id"`
}{highest})
} else {
// This is GET handlerType.
var hit HitType
// Get the hit using again the handler.handlerActionName which may be "flow" or "process"
hit, code, err = a.GetByID(handler.handlerActionName, mux.Vars(r)["id"], r)
if code != 200 || err != nil {
return code, err
}
// Do the un-marshalling.
err = json.Unmarshal(*hit.Source, ob)
if err != nil {
return 500, err
}
// We have set the handler.elastible to be an interface type
// which will have the SetESID function that will set the ESID in the
// underlying type that will be passed on runtime.
// So the ESID will be set for both the Flow and the Process types.
// This interface idea was given inside an earlier answer by
// https://stackoverflow.com/users/7426/adrian
handler.elastible.SetESID(hit.id)
return sendResponse(handler.elastible)
}
}
}
And you would setup your mux end points using the following code.
// This was your first function. "CreateFlow"
api.Handle("/createFlow/{id:[0-9]+}", handlers.AppHandler{
context, CreateHandler(Handler{
elastible: &Flow{},
handlerActionName: "flow",
handlerType: "CREATE",
}),
}).Methods("GET")
// This was your second function. "CreateProcess"
api.Handle("/createProcess/{id:[0-9]+}", handlers.AppHandler{
context, CreateHandler(Handler{
elastible: &Process{},
handlerActionName: "process",
handlerType: "CREATE",
}),
}).Methods("GET")
// This was your third function. "GetFlow"
api.Handle("/getFlow/{id:[0-9]+}", handlers.AppHandler{
context, CreateHandler(Handler{
elastible: &Flow{},
handlerActionName: "flow",
handlerType: "GET",
}),
}).Methods("GET")
// This was your fourth function. "GetProcess"
api.Handle("/getProcess/{id:[0-9]+}", handlers.AppHandler{
context, CreateHandler(Handler{
elastible: &Process{},
handlerActionName: "process",
handlerType: "GET",
}),
}).Methods("GET")
Hope it helps!
Related
I am leaning to write unit tests and I was wondering the correct way to unit test a basic http.get request.
I found an API online that returns fake data and wrote a basic program that gets some user data and prints out an ID:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type UserData struct {
Meta interface{} `json:"meta"`
Data struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Gender string `json:"gender"`
Status string `json:"status"`
} `json:"data"`
}
func main() {
resp := sendRequest()
body := readBody(resp)
id := unmarshallData(body)
fmt.Println(id)
}
func sendRequest() *http.Response {
resp, err := http.Get("https://gorest.co.in/public/v1/users/1841")
if err != nil {
log.Fatalln(err)
}
return resp
}
func readBody(resp *http.Response) []byte {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
return body
}
func unmarshallData(body []byte) int {
var userData UserData
json.Unmarshal(body, &userData)
return userData.Data.ID
}
This works and prints out 1841. I then wanted to write some tests that validate that the code is behaving as expected, e.g. that it correctly fails if an error is returned, that the data returned can be unmarshalled. I have been reading online and looking at examples but they are all far more complex that what I feel I am trying to achieve.
I have started with the following test that ensures that the data passed to the unmarshallData function can be unmarshalled:
package main
import (
"testing"
)
func Test_unmarshallData(t *testing.T) {
type args struct {
body []byte
}
tests := []struct {
name string
args args
want int
}{
{name: "Unmarshall", args: struct{ body []byte }{body: []byte("{\"meta\":null,\"data\":{\"id\":1841,\"name\":\"Piya\",\"email\":\"priya#gmai.com\",\"gender\":\"female\",\"status\":\"active\"}}")}, want: 1841},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := unmarshallData(tt.args.body); got != tt.want {
t.Errorf("unmarshallData() = %v, want %v", got, tt.want)
}
})
}
}
Any advise on where to go from here would be appreciated.
before moving on to the testing, your code has a serious flow, which will become a problem if you don't take care about it in your future programming tasks.
https://pkg.go.dev/net/http See the second example
The client must close the response body when finished with it
Let's fix that now (we will have to come back on this subject later), two possibilities.
1/ within main, use defer to Close that resource after you have drained it;
func main() {
resp := sendRequest()
defer body.Close()
body := readBody(resp)
id := unmarshallData(body)
fmt.Println(id)
}
2/ Do that within readBody
func readBody(resp *http.Response) []byte {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
return body
}
Using a defer is the expected manner to close the resource. It helps the reader to identify the lifetime span of the resource and improve readability.
Notes : I will not be using much of the table test driven pattern, but you should, like you did in your OP.
Moving on to the testing part.
Tests can be written under the same package or its fellow version with a trailing _test, such as [package target]_test. This has implications in two ways.
Using a separate package, they will be ignored in the final build. Which will help to produce smaller binaries.
Using a separate package, you test the API in a black box manner, you can access only the identifiers it explicitly exposes.
Your current tests are white boxed, meaning you can access any declaration of main, public or not.
About sendRequest, writing a test around this is not very interesting because it does too little, and your tests should not be written to test the std library.
But for the sake of the demonstration, and for good reasons we might want to not rely on external resources to execute our tests.
In order to achieve that we must make the global dependencies consumed within it, an injected dependency. So that later on, it is possible to replace the one thing it depends on to react, the http.Get method.
func sendRequest(client interface{Get() (*http.Response, error)}) *http.Response {
resp, err := client.Get("https://gorest.co.in/public/v1/users/1841")
if err != nil {
log.Fatalln(err)
}
return resp
}
Here i use an inlined interface declaration interface{Get() (*http.Response, error)}.
Now we can add a new test which injects a piece of code that will return exactly the values that will trigger the behavior we want to test within our code.
type fakeGetter struct {
resp *http.Response
err error
}
func (f fakeGetter) Get(u string) (*http.Response, error) {
return f.resp, f.err
}
func TestSendRequestReturnsNilResponseOnError(t *testing.T) {
c := fakeGetter{
err: fmt.Errorf("whatever error will do"),
}
resp := sendRequest(c)
if resp != nil {
t.Fatal("it should return a nil response when an error arises")
}
}
Now run this test and see the result. It is not conclusive because your function contains a call to log.Fatal, which in turns executes an os.Exit; We cannot test that.
If we try to change that, we might think we might call for panic instead because we can recover.
I don't recommend doing that, in my opinion, this is smelly and bad, but it exists, so we might consider. This is also the least possible change to the function signature. Returning an error would break even more the current signatures. I want to minimize this for that demonstration. But, as a rule of thumb, return an error and always check them.
In the sendRequest function, replace this call log.Fatalln(err) with panic(err) and update the test to capture the panic.
func TestSendRequestReturnsNilResponseOnError(t *testing.T) {
var hasPanicked bool
defer func() {
_ = recover() // if you capture the output value or recover, you get the error gave to the panic call. We have no use of it.
hasPanicked = true
}()
c := fakeGetter{
err: fmt.Errorf("whatever error will do"),
}
resp := sendRequest(c)
if resp != nil {
t.Fatal("it should return a nil response when an error arises")
}
if !hasPanicked {
t.Fatal("it should have panicked")
}
}
We can now move on to the other execution path, the non error return.
For that we forge the desired *http.Response instance we want to pass into our function, we will then check its properties to figure out if what the function does is inline with what we expect.
We will consider we want to ensure it is returned unmodified : /
Below test only sets two properties, and I will do it to demonstrate how to set the Body with a NopCloser and strings.NewReader as it is often needed later on using the Go language;
I also use reflect.DeepEqual as brute force equality checker, usually you can be more fine grained and get better tests. DeepEqual does the job in this case but it introduces complexity that does not justify systematic use of it.
func TestSendRequestReturnsUnmodifiedResponse(t *testing.T) {
c := fakeGetter{
err: nil,
resp: &http.Response{
Status: http.StatusOK,
Body: ioutil.NopCloser(strings.NewReader("some text")),
},
}
resp := sendRequest(c)
if !reflect.DeepEqual(resp, c.resp) {
t.Fatal("the response should not have been modified")
}
}
At that point you may have figured that this small function sendRequest is not good, if you did not I ensure you it is not. It does too little, it merely wraps the http.Get method and its testing is of little interest for the survival of the business logic.
Moving on to readBody function.
All remarks that applied for sendRequest apply here too.
it does too little
it os.Exits
One thing does not apply. As the call to ioutil.ReadAll does not rely on external resources, there is no point in attempting to inject that dependency. We can test around.
Though, for the sake of the demonstration, it is the time to talk about the missing call to defer resp.Body.Close().
Let us assume we go for the second proposition made in introduction and test for that.
The http.Response struct adequately exposes its Body recipient as an interface.
To ensure the code calls for the `Close, we can write a stub for it.
That stub will record if that call was made, the test can then check for that and trigger an error if it was not.
type closeCallRecorder struct {
hasClosed bool
}
func (c *closeCallRecorder) Close() error {
c.hasClosed = true
return nil
}
func (c *closeCallRecorder) Read(p []byte) (int, error) {
return 0, nil
}
func TestReadBodyCallsClose(t *testing.T) {
body := &closeCallRecorder{}
res := &http.Response{
Body: body,
}
_ = readBody(res)
if !body.hasClosed {
t.Fatal("the response body was not closed")
}
}
Similarly, and for the sake of the demonstration, we might want to test if the function has called for Read.
type readCallRecorder struct {
hasRead bool
}
func (c *readCallRecorder) Read(p []byte) (int, error) {
c.hasRead = true
return 0, nil
}
func TestReadBodyHasReadAnything(t *testing.T) {
body := &readCallRecorder{}
res := &http.Response{
Body: ioutil.NopCloser(body),
}
_ = readBody(res)
if !body.hasRead {
t.Fatal("the response body was not read")
}
}
We an also verify the body was not modified in betwen,
func TestReadBodyDidNotModifyTheResponse(t *testing.T) {
want := "this"
res := &http.Response{
Body: ioutil.NopCloser(strings.NewReader(want)),
}
resp := readBody(res)
if got := string(resp); want != got {
t.Fatal("invalid response, wanted=%q got %q", want, got)
}
}
We have almost done, lets move one to the unmarshallData function.
You have already wrote a test about it. It is okish, though, i would write it this way to make it leaner:
type UserData struct {
Meta interface{} `json:"meta"`
Data Data `json:"data"`
}
type Data struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Gender string `json:"gender"`
Status string `json:"status"`
}
func Test_unmarshallData(t *testing.T) {
type args struct {
body []byte
}
tests := []UserData{
UserData{Data: Data{ID: 1841}},
}
for _, u := range tests {
want := u.ID
b, _ := json.Marshal(u)
t.Run("Unmarshal", func(t *testing.T) {
if got := unmarshallData(b); got != want {
t.Errorf("unmarshallData() = %v, want %v", got, want)
}
})
}
}
Then, the usual apply :
don't log.Fatal
what are you testing ? the marshaller ?
Finally, now that we have gathered all those pieces, we can refactor to write a more sensible function and re use all those pieces to help us testing such code.
I won't do it, but here is a starter, which still panics, and I still don't recommend, but the previous demonstration has shown everything needed to test a version of it that returns an error.
type userFetcher struct {
Requester interface {
Get(u string) (*http.Response, error)
}
}
func (u userFetcher) Fetch() int {
resp, err := u.Requester.Get("https://gorest.co.in/public/v1/users/1841") // it does not really matter that this string is static, using the requester we can mock the response, its body and the error.
if err != nil {
panic(err)
}
defer resp.Body.Close() //always.
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
var userData UserData
err = json.Unmarshal(body, &userData)
if err != nil {
panic(err)
}
return userData.Data.ID
}
I have a set of functions, which uses the pool of objects. This pool has been mocked. It works fine in most of the cases. But in some functions i call the methods of objects from the pool. So i need to mock this objects too.
Lets say:
// ObjectGeter is a interface that is mocked
type ObjectGeter interface {
GetObject(id int) ObjectType, error
}
// this function is under test
func SomeFunc(og ObjectGeter,id int, otherArgument SomeType) error {
// some actions with otherArgument
// and may be return an error
obj, err := og.GetObject(id)
if err !=nil {
return errors.New("GetObject error")
}
rezult, err := obj.SomeMethod()
if err !=nil {
return errors.New("One of internal errors")
}
return rezult, nil
}
Is there a way to test whole this function? I can create interface SomeMethoder which wraps the SomeMethod(), but i can't find the way how to assign it to obj inside SomeFunc without changing the signature of GetObject to GetObject(id int) SomeMethoder,error.
Currently i see the one approach - testing by a parts.
The only solution i'v found without of changing of paradigm is a wrapper. It is pretty trivial but may be some one will need it once.
Originally i have some type:
type PoolType struct {...}
func (p *PoolType)GetObject(id int) (ObjectType, error) {...}
and interface, that wraps PoolType.GetObject and that i'v mocked.
Now i have the interface:
type SomeMethoder interface {
SomeMethod() (ResultType, error)
}
to wrap object returned by PoolType.GetObject().
To produce it i have interface:
type ObjectGeter interface {
GetObject(id int) (SomeMethoder, error)
}
and type
type MyObjectGeter struct {
pool *PoolType
}
func New(pool *PoolType) *MyObjectGeter {
return &MyObjectGeter{pool: pool}
}
func (p *MyObjectGeter)GetObject(id int) (SomeMethoder, error) {
return p.pool.GetObject(id)
}
that implements it.
So:
// this function is under test
func SomeFunc(og ObjectGeter,id int, otherArgument SomeType) error {
// some actions with otherArgument
// and may be return an error
iface, err := og.GetObject(id)
if err !=nil {
return errors.New("GetObject error")
}
rezult, err := iface.SomeMethod()
if err !=nil {
return errors.New("One of internal errors")
}
return rezult, nil
}
is called by
og := New(pool)
SomeFunc(og,id,otherArgument)
in real work.
After all to test whole SomeFunc i have to:
func TestSomeFuncSuccess (t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
objectGeter := mocks.NewMockObjectGeter(controller)
someMethoder := mocks.NewMockSomeMethoder(controller)
gomock.InOrder(
args.objectGeter.EXPECT().
GetObject(correctIdCOnst).
Return(someMethoder, nil),
args.someMethoder.EXPECT().
SomeMethod().
Return(NewResultType(...),nil).
Times(args.test.times[1]),
)
result, err := SomeFunc(objectGeter,correctIdCOnst,otherArgumentConst)
// some checks
}
So, the only untested part is MyObjectGeter.GetObject that is enough for me.
I am trying to add context to Authorization middleware. The ContextHandler is a handler which will be passed to api handlers to take care of connections and config variables. A struct Method ServeHTTP also has been added to the ContextHandler so that it satisfies the net/Http interface for handling requests properly.
CheckAuth is the middle ware which takes in the request to check token validation etc, If token is valid, executes the ServeHTTP method and if not, Returns the appropriate error in the response.
Code compiles, but i am getting error in the ServeHTTP method.
type ContextHandler struct {
*AppContext
Handler func(*AppContext, http.ResponseWriter, *http.Request)(int, error)
}
type AppContext struct {
Db *mgo.Session
Config *simplejson.Json
}
func (ah *ContextedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
status, err := ah.handler(ah.AppContext, w, r)
if err != nil {
switch status {
case http.StatusNotFound:
http.NotFound(w, r)
case http.StatusInternalServerError:
http.Error(w, http.StatusText(status), status)
default:
http.Error(w, http.StatusText(405), 405)
}}}
func CheckAuth(h http.Handler) http.Handler {
log.Println("Entered in CheckAuth")
f := func( w http.ResponseWriter, r *http.Request) {
authorizationToken := r.Header.Get("Authorization")
if authorizationToken != ""{
secret := []byte("somejunk")
var credentials authorization
token, err := jwt.ParseWithClaims(authorizationToken, &credentials, func(t *jwt.Token) (interface{}, error) {
return []byte(secret), nil
})
if err == nil && token.Valid {
//If everything is fine serve the Http request
h.ServeHTTP( w, r)
return
} else {
//Some response returned
json.NewEncoder(w).Encode(response)
return
}
//Check if user exists in the database
if dberr != nil {
//SOmeresponse to be returned
json.NewEncoder(w).Encode(response)
return
}
}else{
response := simplejson.New()
//response authorization header is missing
json.NewEncoder(w).Encode(response)
return
}
}
return http.HandlerFunc(f)
}
func Initdb(configfile *simplejson.Json) *mgo.Session {
//return mongodbsession, copy and close while using it
}
In main.go file in the parent package
func main() {
var FileUploadContextHandler *ContextedHandler = &ContextedHandler{&context, filesystem.FileUpload}
router.Methods("POST").Path("/decentralizefilesystem/fileupload").Name("FileUpload").Handler(CheckAuth(FileUploadContextHandler))
}
I am getting this error
2018/07/08 20:45:38 http: panic serving 127.0.0.1:52732: runtime error: invalid memory address or nil pointer dereference
goroutine 35 [running]:
net/http.(*conn).serve.func1(0xc4202ce140)
/usr/local/go/src/net/http/server.go:1726 +0xd0
panic(0x6fe680, 0x92cb10)
/usr/local/go/src/runtime/panic.go:502 +0x229
gitlab.com/mesha/Gofeynmen/vendor/gopkg.in/mgo%2ev2.(*Session).Copy(0x0, 0x7ff9485fb060)
/home/feynman/goworkspace/src/gitlab.com/mesha/Gofeynmen/vendor/gopkg.in/mgo.v2/session.go:1589 +0x22
gitlab.com/mesha/Gofeynmen/appsettings.CheckAuth.func1(0x7ff9485fb060, 0xc420276300, 0xc4202e4200)
/home/feynman/goworkspace/src/gitlab.com/mesha/Gofeynmen/appsettings/appsettings.go:115 +0x361
net/http.HandlerFunc.ServeHTTP(0xc420290180, 0x7ff9485fb060, 0xc420276300, 0xc4202e4200)
/usr/local/go/src/net/http/server.go:1947 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc42024a310, 0x7ff9485fb060, 0xc420276300, 0xc4202e4200)
/home/feynman/goworkspace/src/github.com/gorilla/mux/mux.go:162 +0xed
github.com/gorilla/handlers.loggingHandler.ServeHTTP(0x7a8120, 0xc42000e018, 0x7a7b20, 0xc42024a310, 0x7aad60, 0xc4202f0000, 0xc4202e4000)
/home/feynman/goworkspace/src/github.com/gorilla/handlers/handlers.go:69 +0x123
github.com/gorilla/handlers.(*cors).ServeHTTP(0xc4202c4090, 0x7aad60, 0xc4202f0000, 0xc4202e4000)
/home/feynman/goworkspace/src/github.com/gorilla/handlers/cors.go:52 +0xa3b
net/http.serverHandler.ServeHTTP(0xc4202da0d0, 0x7aad60, 0xc4202f0000, 0xc4202e4000)
/usr/local/go/src/net/http/server.go:2694 +0xbc
net/http.(*conn).serve(0xc4202ce140, 0x7ab120, 0xc42025e100)
/usr/local/go/src/net/http/server.go:1830 +0x651
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:2795 +0x27b
It's likely an attempt to dereference ah from (ah *ContextedHandler), when ah is not a pointer to a ContextedHandler.
The types in this assignment don't match up:
var FileUploadContextHandler *ContextedHandler =
ContextedHandler{&context, filesystem.FileUpload}
On the left side you have type *ContextedHandler. On the right side you have type ContextedHandler.
Did you mean
var FileUploadContextHandler *ContextedHandler =
&ContextedHandler{&context, filesystem.FileUpload}
Or did you mean
var FileUploadContextHandler ContextedHandler =
ContextedHandler{&context, filesystem.FileUpload}
?
The argument passed to the CheckAuth function appears to not match the function signature either:
CheckAuth(FileUploadContextHandler)
FileUploadContextHandler is type *ContextedHandler. The function signature is:
func CheckAuth(h contextHandlerFunc) contextHandlerFunc
The type definition of contextHandlerFunc does not appear to be part of the code you shared.
A problem with this line:
router.Methods("POST").Path("/decentralizefilesystem/fileupload").Name("FileUpload").Handler(CheckAuth(FileUploadContextHandler))
...would be easier to track down if you broke it up into variable assignments on several lines and then figured out which line the panic pointed to.
Hi guys fairly new to Golang, I understand that interfaces are kind of like contracts that guarantee that certain things will operate a certain way, thats cool and all, and if I make a local copy of it I can basically re-write how it operates (From what I understand, please correct me if I'm wrong)
Here is what I have so far
package register
import (
"log"
"net/http"
"github.com/yohcop/openid-go"
)
var nonceStore = &openid.SimpleNonceStore{
Store: make(map[string][]*openid.Nonce)}
var discoveryCache = &SimpleDiscoveryCache{}
type DiscoveredInfo interface {
OpEndpoint() string
OPLocalID() string
ClaimedID() string
}
type SimpleDiscoveredInfo struct {
opEndpoint, opLocalID, claimedID string
}
type SimpleDiscoveryCache map[string]DiscoveredInfo
func (s *SimpleDiscoveryCache) Put(id string, info DiscoveredInfo) {
db := common.ConnectDB()
rows, err := db.Query("INSERT INTO discovery_cache SET id=?, opendpoint=?, oplocalid=?, claimedid=?",
id, info.OpEndpoint(), info.OPLocalID(), info.ClaimedID())
if err != nil {
panic("Error: " + err.Error())
}
log.Println(rows)
}
func (s *SimpleDiscoveryCache) Get(id string) DiscoveredInfo {
db := common.ConnectDB()
rows, err := db.Query("SELECT FROM discovery_cache WHERE id=?", id)
if err != nil {
panic("Error: " + err.Error())
}
log.Println(rows)
var opEndpoint, opLocalID, claimedID string
for rows.Next() {
err := rows.Scan(&opEndpoint, &opLocalID, &claimedID)
if err != nil {
panic("Help!")
}
}
return &SimpleDiscoveredInfo{
opEndpoint, opLocalID, claimedID,
}
}
func DiscoverHandler(w http.ResponseWriter, r *http.Request) {
url, err := openid.RedirectURL("http://steamcommunity.com/openid", "http://localhost:1337/login/return", "http://localhost")
if err != nil {
http.Error(w, "Failed to login", 500)
}
http.Redirect(w, r, url, 303)
}
func CallbackHandler(w http.ResponseWriter, r *http.Request) {
fullUrl := "http://localhost:1337" + r.URL.String()
id, err := openid.Verify(fullUrl, discoveryCache, nonceStore)
if err != nil {
http.Error(w, "Failed", 500)
}
log.Println(id)
}
Basically I am trying to make my own DiscoveryCache so that it uses a database instead of memory for storage (as instructed to do by the Go-OpenID package located here: https://github.com/yohcop/openid-go
The part I'm trying to recreate is located here: https://github.com/yohcop/openid-go/blob/master/discovery_cache.go
Now I have done (what I assume) everything that should need doing to make this work, but I keep getting this error:
controllers/register/register.go:60: cannot use SimpleDiscoveredInfo literal (type *SimpleDiscoveredInfo) as type openid.DiscoveredInfo in return argument:
*SimpleDiscoveredInfo does not implement openid.DiscoveredInfo (missing ClaimedID method)
controllers/register/register.go:78: cannot use discoveryCache (type *SimpleDiscoveryCache) as type openid.DiscoveryCache in argument to openid.Verify:
*SimpleDiscoveryCache does not implement openid.DiscoveryCache (wrong type for Put method)
have Put(string, DiscoveredInfo)
want Put(string, openid.DiscoveredInfo)
If anybody could inform me on what I have done wrong that would be much appreciated. Thanks! If you need any more information please let me know.
SimpleDiscoveredInfo doesn't implement the interface's methods, you need something like this:
func (sdi *SimpleDiscoveredInfo) OpEndpoint() string { return sdi.opEndpoint }
func (sdi *SimpleDiscoveredInfo) OpLocalID() string { return sdi.opLocalID }
func (sdi *SimpleDiscoveredInfo) ClaimedID() string { return sdi.claimedID }
var _ openid.DiscoveredInfo = (*SimpleDiscoveredInfo)(nil)
http://play.golang.org/p/qVTTKfhNHu
For
controllers/register/register.go:78: cannot use discoveryCache (type *SimpleDiscoveryCache) as type openid.DiscoveryCache in argument to openid.Verify:
*SimpleDiscoveryCache does not implement openid.DiscoveryCache (wrong type for Put method)
have Put(string, DiscoveredInfo)
want Put(string, openid.DiscoveredInfo)
Your types need to return openid.DiscoveredInfo not DiscoveredInfo.
I am parsing a form and have written a number of functions func parseAndValidateX(val string) (T, err) where T is any type.
Now I would like to write a closure func catchError(T, Error) T, so that I can do something like:
errors []Error
func catchError(val T, err Error) T {
if err != nil {
//append err to errors
}
return val
}
data = MyStruct {
Age = catchError(parseAndValidateAge("5")) // Age is a int
DistanceFromHome = catchError(parseAndValidatePi("3.14")) // DistanceFromHome is a float
Location = catchError(parseAndValidatePi("3.14,2.0")) //Location is a custom Struct
}
if len(errors) > 0 {
// o, oh
}
Is this possible in Go? How can this be done easily/idiomatically?
Nope; you cannot do that since Go has no parametric polymorphism for user-defined functions. All you can do is take and return interface{} and add type assertions at the call sites.
Everything in Go is type-safe if you don't use the unsafe package, so you don't have to worry about that. A type assertion will fail at runtime instead of at compile-time, though.
If you are willing to violate DRY, though:
type errorList []Error
func (l *errorList) addIfNotNil(err Error) {
if err != nil {
*l = append(*l, err)
}
}
func (l *errorList) int(x int, err Error) int {
l.addIfNotNil(err)
return x
}
func (l *errorList) float32(x float32, err Error) float32 {
l.addIfNotNil(err)
return x
}
list := errorList([]Error{})
data := MyStruct{
Age: list.int(parseAndValidateAge("5")),
DistanceFromHome: list.float32(parseAndValidatePi("3.14")),
}