2017年3月1日水曜日

go-swagger でエラーハンドリングする方法

概要

使用するアプリケーションはこれまでに作成した TODO アプリを使用します

環境

  • CentOS 6.7 64bit
  • go-swagger dev
  • golang 1.6

swagger.yml にエラーの定義を追加

  • paths -> / -> post -> responses -> 400

に以下を定義します

400:
  description: BadRequest
  schema:
    $ref: "#/definitions/error"

そしてこれで再度コードを生成し直します

  • swagger validate swagger.yml
  • swagger generate server -A TodoList -f swagger.yml

ソースコード修正

restapi/configure_todo_list.go を編集します
POST の部分を以下のように修正することで定義した 400 用の関数を使うことができます

api.TodosAddOneHandler = todos.AddOneHandlerFunc(func(params todos.AddOneParams) middleware.Responder {
        if err := addItem(params.Body); err != nil {
                return todos.NewAddOneBadRequest().WithPayload(&models.Error{Code: 400, Message: swag.String(err.Error())})
        }
        testQueue.Put("testpayload")
        return todos.NewAddOneCreated().WithPayload(params.Body)
})

ポイントは 400 の定義を swagger.yml に追加することで restapi/operations/todos/add_one_responses.go に NewAddOneBadRequest というメソッドが追加されていることです
これを使うことでステータスコードが既に設定されたレスポンスを返却することができます

WithPayload でレスポンスのボディを設定することができます
今回はモデルにそれっぽい値を設定してレスポンスボディとしています

  • &models.Error{Code: 400, Message: swag.String(err.Error())}

ちょっとおまけ

ここで思うのがいちいち Code: 400 という感じでステータスコードを決め打ちするのは面倒ということです
addItem は github.com/go-openapi/errors というパッケージの Error オブジェクトを返します
このオブジェクトはステータスコードも持っています

なので addItem 関数の返り値を errors.Error のように修正してモデルからエラーオブジェクトを生成するときに以下のように修正します

  • addItem 関数
func addItem(item *models.Item) errors.Error {
        if item == nil {
                return errors.New(400, "item must be present")
        }

        itemsLock.Lock()
        defer itemsLock.Unlock()

        newID := newItemID()
        item.ID = newID
        items[newID] = item

        return nil
}
  • api.TodosAddOneHandler 関数
&models.Error{Code: err.Code(), Message: swag.String(err.Error())}

err.Code() で返ってくる型が int32 なので swagger.yml の設定も以下のように変更する必要があります

swagger.yml の definitions -> error の format を int32 に変更する必要があります

error:
  type: object
  required:
    - message
  properties:
    code:
      type: integer
      format: int32
    message:
      type: string

swagger.yml を修正しているのでビルドするときは validate -> generate してください
これでロジック側で生成したエラーオブジェクトを configureAPI 側で返すだけなのでキレイなコードになると思います

最後に

go-swagger でエラーハンドリングする方法を紹介しました
基本的には swagger.yml で定義したステータスコード用の関数ができるのでちゃんとそれを使うようにするだけです

エラーを生成するのはあくまでもロジック側のコード (今回だと addItem) で、それを configure_todo_list.go の configureAPI 側で受け取って返却する流れがきれいな流れかなと思います

0 件のコメント:

コメントを投稿