Skip to content

Instantly share code, notes, and snippets.

@hamakn
Last active April 6, 2018 05:09
Show Gist options
  • Save hamakn/f67f0e6bf9a3799672d7612aee8c6c41 to your computer and use it in GitHub Desktop.
Save hamakn/f67f0e6bf9a3799672d7612aee8c6c41 to your computer and use it in GitHub Desktop.
my golang レシピブック

negroniでhttpをserveする

package main
  
import (
  "bytes"
  "fmt"
  "net/http"
  "net/http/httptest"

  "github.com/urfave/negroni"
)

func NewRouter() *negroni.Negroni {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.Classic() // Includes some default middlewares
  n.UseHandler(mux)

  return n
}

func main() {
  // http.ListenAndServe(":3000", NewRouter())
  // => localhost:3000 で "Welcome to the home page!"

  response := httptest.NewRecorder()
  response.Body = new(bytes.Buffer)
 
  n := NewRouter()
 
  req, _ := http.NewRequest("GET", "/", nil)
  n.ServeHTTP(response, req)
 
  fmt.Println(req)
  fmt.Println(response)
}

SHA256(Rubyで言うbase64digestとhexdigest)

package main
  
import (
  "crypto/sha256"
  "encoding/base64"
  "encoding/hex"
  "fmt"
)

func main() {
  h := sha256.New()
  h.Write([]byte(""))
  b := h.Sum(nil)

  s := base64.URLEncoding.EncodeToString(b)
  fmt.Println(s)
  // => 47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU=
  // ruby -r "digest" -e "p Digest::SHA256.base64digest(\"\")" に一致

  fmt.Println(hex.EncodeToString(b))
  // => e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  // ruby -r "digest" -e "p Digest::SHA256.hexdigest(\"\")" に一致
}

sliceをinterface{}で受けて要素のfieldを取得したりfuncを呼ぶ

package main

import (
	"fmt"
	"reflect"
)

type Animal interface {
	Say() string
}

type Dog struct {
	name string
}

func (d *Dog) Say() string {
	return "bow"
}

func main() {
	dogs := []*Dog{{"pochi"}, {"mukku"}, {"mari"}, {"kotaro"}, nil}
	sub(dogs)
	// =>
	// name: pochi, said: bow
	// name: mukku, said: bow
	// name: mari, said: bow
	// name: kotaro, said: bow
}

func sub(src interface{}) {
	// ValueOf: srcの実体をreflect.Value型(またはそのポインタ)に変換する
	// Indirect: ポインタであれば実体にする
	v := reflect.Indirect(reflect.ValueOf(src))

	if v.Type().Kind() != reflect.Slice {
		// slice以外であれば何もしない
		return
	}

	// interface型の取得
	animalInterface := reflect.TypeOf((*Animal)(nil)).Elem()
	if !reflect.TypeOf(src).Elem().Implements(animalInterface) {
		// sliceの要素が特定のinterface(今回はAnimal)を実装していなければ何もしない
		return
	}

	// sliceのloop
	for i := 0; i < v.Len(); i++ {
		e := v.Index(i)

		// nilの際はcontinueする
		if reflect.Indirect(e).IsValid() == false {
			continue
		}

		// methodを取得して呼び出す
		m := e.MethodByName("Say")
		r := m.Call([]reflect.Value{})

		// Interface, Pointerを変換する
		if e.Kind() == reflect.Interface {
			e = reflect.Indirect(e.Elem())
		} else if e.Kind() == reflect.Ptr {
			e = e.Elem()
		}
		if e.Kind() == reflect.Ptr {
			e = reflect.Indirect(e.Elem())
		}

		// 特定field(今回はname)の値を取得する
		name := ""
		for j := 0; j < e.NumField(); j++ {
			tf := e.Type().Field(j)

			if tf.Name == "name" {
				ef := e.Field(j)

				switch ef.Kind() {
				case reflect.String:
					name = ef.String()
				}

				break
			}
		}

		fmt.Printf("name: %v, said: %v\n", name, r[0])
	}
}

(JSONの)型で場合分けする

package main
  
import (
  "encoding/json"
  "fmt"
  "strings"
)

func main() {
  testCases := []struct {
    json string
  }{
    {json: "{\"maybeString\":\"Stringだよ\"}"},
    {json: "{\"maybeString\":[\"残念Arrayでした\"]}"},
  }

  for _, testCase := range testCases {
    var data interface{}
    jsonIoReader := strings.NewReader(testCase.json)
    err := json.NewDecoder(jsonIoReader).Decode(&data)

    fmt.Println("---")
    fmt.Println(data)
    fmt.Println(err)

    maybeString := data.(map[string]interface{})["maybeString"]
    if value, ok := maybeString.(string); ok {
      fmt.Println("これはStringです")
      fmt.Println(value)
    } else if value, ok := maybeString.([]interface{}); ok {
      if value, ok := value[0].(string); ok {
        fmt.Println("これはStringのArrayです")
        fmt.Println(value)
      }
    }
  }
}
// =>
// ---
// map[maybeString:Stringだよ]
// <nil>
// これはStringです
// Stringだよ
// ---
// map[maybeString:[残念Arrayでした]]
// <nil>
// これはStringのArrayです
// 残念Arrayでした

JSONをvalidationする

package json

import (
	"encoding/json"
	"fmt"
	"strings"
	"testing"

	"github.com/stretchr/testify/require"
	validator "gopkg.in/go-playground/validator.v9"
)

type IntParams struct {
	ZeroToTen *int `json:"zero_to_ten" validate:"required,min=0,max=10"`
}

func TestIntParams(t *testing.T) {
	testCases := []struct {
		JSON               string
		HasParseError      bool
		HasValidationError bool
	}{
		{
			// OK1
			"{\"zero_to_ten\":0}",
			false,
			false,
		},
		{
			// OK2
			"{\"zero_to_ten\":10}",
			false,
			false,
		},
		{
			// NG1
			"{\"zero_to_ten\":-1}",
			false,
			true,
		},
		{
			// NG2
			"{\"zero_to_ten\":11}",
			false,
			true,
		},
		{
			// NG3
			"{}",
			false,
			true,
		},
		{
			// NG4
			"{\"zero_to_ten\":\"aaa\"}",
			true,
			false,
		},
		{
			// NG5
			"{\"zero_to_ten\":null}",
			false,
			true,
		},
	}

	v := validator.New()
	for _, testCase := range testCases {
		p := IntParams{}
		err := json.NewDecoder(strings.NewReader(testCase.JSON)).Decode(&p)

		if testCase.HasParseError {
			require.NotNil(t, err)
			fmt.Println(err)

		} else {
			require.Nil(t, err)

			err = v.Struct(p)
			fmt.Println(p)

			if testCase.HasValidationError {
				require.NotNil(t, err)
				fmt.Println(err)
			} else {
				require.Nil(t, err)
			}
		}
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment