【Go】Echo アプリログ出力処理(複数ファイルへ)

実際使おうとすると調べる内容が細かい。。けどメモ。
logrusというのを使ってみる。ローテションはとりあえず考えない。

log/log.go

package log

import (
  "os"
  "fmt"
  "github.com/Sirupsen/logrus"
)

var AppLog = logrus.New()
var AppLog2 = logrus.New()

func init() {

  // Log1
  file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  if err != nil {
    panic(fmt.Sprintf("[Error]: %s", err))
  }

  AppLog.Out = file
  AppLog.Formatter = &logrus.JSONFormatter{}

  // Log2
  file, err := os.OpenFile("app2.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  if err != nil {
    panic(fmt.Sprintf("[Error]: %s", err))
  }

  AppLog2.Out = file
  AppLog2.Formatter = &logrus.JSONFormatter{}
}

main.go

package main

import (
  "app/log"
  "github.com/labstack/echo"
)

func main() {
  e := echo.New()

  log.AppLog.Info("Log1 Output")
  log.AppLog2.Info("Log2 Output")

  e.Start(":8080")
}

以上です

【Go】Echo InternalServerErrorとNotFoundエラーを発生させる

こんなことできるのか

main.go

package main

import (
  "net/http"
  "github.com/labstack/echo"
)

func main() {
  e := echo.New()

  e.GET("/users", func(c echo.Contet) error {
    // エラーを返す
    return echo.NewHTTPError(http.StatusInternalServerError, "Server Error")
    // return echo.NewHTTPError(http.StatusNotFound, "Not Found")
  })

  e.Start(":8080")
}

以上です

【Go】Echo エラー処理を実装する

apiサーバーの実装でとりあえずのエラー処理中。とりあえず以下をハンドリングするような想定で。
・ビジネスエラー
・システムエラー
・404エラー
・その他サーバーエラー

ディレクトリ構成はこんな感じ

$ tree -L 3
.
└── app
    ├── controller
    │   └── traking.go
    ├── error
    │   ├── business.go
    │   └── system.go
    ├── handler
    │   └── handler.go
    ├── main.go
独自エラーの実装

Messageはユーザーに伝えるメッセージ。
LogMessageはログとかに残すメッセージ(後で実装する予定)

app/error/system.go

package error

import(
  "fmt"
)

type SystemError struct {
  Message string
  LogMessage string
}

func (err *SystemError) Error() string {
  return fmt.Sprintf("%s", err.Message)
}
エラーハンドリング

とりあえずJSONをかえすところまで実装。

app/handler/handler.go

package handler

import(
  AppErr "app/error"
  "net/http"
  "github.com/labstack/echo"
)

type ApiError struct {
  Status int `json:status`
  Message string `json:message`
}

func JSONErrorHandler(err error, c echo.Context) {
  switch e := err.(type) {
  case *AppErr.BusinessError:
    // Business Error                                                                                                                                                                                              
    c.JSON(
      http.StatusOK, ApiError{
        Status: 200,
        Message: e.Message,
      })
  case *AppErr.SystemError:
      // System Error                                                                                                                                                                                              
      c.JSON(http.StatusOK, ApiError{
        Status: 500,
        Message: e.Message,
      })
  default:
    if he, ok := err.(*echo.HTTPError); ok {
      if he.Code == 404 {
        // 404                                                                                                                                                                                                     
        c.JSON(he.Code, ApiError{
          Status: he.Code,
          Message: "Not Found",
        })
      } else {
        // その他サーバーエラー                                                                                                                                                                                    
        c.JSON(he.Code, ApiError{
          Status: he.Code,
          Message: "System Error",
        })
      }
    }
  }
}

main.go

package main

import (
  AppErr "app/error"
  "app/handler"
)

func main() {
  e := echo.New()

  e.GET("/users", func(c echo.Contet) error {
    return &AppErr.System{ Message: "システムエラーだよ" }
    // return echo.NewHTTPError(http.StatusInternalServerError, "Server Error")
    // return echo.NewHTTPError(http.StatusNotFound, "Not Found")
  })

  e.HTTPErrorHandler = handler.JSONErrorHandler

  e.Start(":8080")
}

とりあえずやりたいことはできた。色々実装したら全然足りなそうだけど一旦はこれで。以上です。

【Go】Echo Controllerを別Packageに分割する

細かい話だけどecho的には特にルールは決まっていなそう。

main.go

package main

import (
  "github.com/labstack/echo"

  "app/controller"
)

func main() {

  e := echo.New()

  e.GET("/members", controller.GetMember())
  e.POST("/members", controller.PostMember())
}

controller/members.go

package controller

import(
  "net/http"                                                                                                                                                                                                       
  
  "github.com/labstack/echo"
)

func GetMember() echo.HandlerFunc {
  return func(c echo.Context) error {
    ・・・
  }
}

func PostMember() echo.HandlerFunc {
  return func(c echo.Context) error {
    ・・・
  }
}

こんな感じでよいのかな。。以上です。

【Go】Echo JSONを返す

echoでjsonを返すサンプル

package main

import(
  "net/http"                                                                                                                                                                                                       
  
  "github.com/labstack/echo"
)

// レスポンスを表す構造体を定義
type Member struct {
  Id int `json:"id"`
  Name string `json:"name"`
}

func main() {

  e := echo.New()
  e.GET("/members", func(c echo.Context) error {
    // Member型のリスト
    members := []Member{
      {Id: 1, Name: "test1"},
      {Id: 2, Name: "test2"}
    }
    return c.JSON(http.StatusOK, members)
  })
}

以上です

macにgoをインストールする手順メモ

1台のPCで複数バージョンのGoを使用したいのでgvm(Go Version Manger)を使用する。

https://github.com/moovweb/gvm
ドキュメントどおりにやったらすんなり入った。Mac使ってるので「Mac OS X Requirements」のコマンド実行

準備

$ brew update
$ brew install mercurial

gvmのインストール 「Installing」のコマンド実行

$ bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

gvmがインストールできたことを確認

$ gvm version
Go Version Manager v1.0.22 installed at /Users/xxxxx/.gvm

goをインストール

# インストール可能なバージョンを調べる
$ gvm listall

# 1.4と1.9のバイナリーをインストールする
$ gvm install go1.4 -B
$ gvm install go1.9 -B

# インストールできたことを確認
$ gvm list
gvm gos (installed)
   go1.4
   go1.9

# バージョンを指定して適用
$ gvm use go1.9

# 適用されたことを確認
$ go version
go1.9 darwin/amd64

とりあえずGoが使える状態になった。
インストールのところで「-B」をつけるとバイナリーをそのままインストールすることになるのだが、これつけないでインストールしようとしたらエラーが出たのでめんどくさくなってこの形としてしまった。。

以上です

labelクリックでinputにfocusする iOS対応

スマホで言えばこんなUIの入力フォーム。
この場合、画面の左半分がlabelで右半分がinput。

f:id:yoppy0066:20171020234919p:plain

で、気がきかないから気にしてなかったのだが、labelをタップしても入力できないということで親切でないということで修正しようとしたらちょっとはまったのでメモしておく。

Labelをクリックしたらinputにfocusさせる(失敗)

javascriptで無理やりやろうとした。PCやandroidで確認してたらうまくいったのだが、何故かiPhonesafariでうまくいかず断念。

Labelとinputを関連づける(成功)

labelとinputの関連づけってよくやってるけど何の意味があるのかと思っていたのだが。こういうことなんですね。。
ちなみにCSSの「cusor:pointer」はこれがないとiPhoneで動かないみたい。

HTML

<label for="nickname">ニックネーム</label>
<input type="text" id="nickname" />

CSS

label {
  cursor: pointer;
}

以上です