2016-12-31 13 views
1

我有錯誤的數組(錯誤類型),但是當我嘗試在JSON格式返回客戶端,它到達空。如何錯誤的數組轉換爲JSON在Go

它的建立是這樣的:

var (
    ErrEmptyName = errors.New("Nome não pode ser vázio") 
    ErrInvalidType = errors.New("Tipo de pessoa inválido") 
) 

func (p Person) Validate() []error { 

    var errors []error 

    if govalidator.IsNull(p.Name) { 
     errors = append(errors, ErrEmptyName) 
    } 

    if p.Type != "F" && p.Type != "J" { 
     errors = append(errors, ErrInvalidType) 
    } 

    return errors 
) 

在我的控制器:

err := person.Validate() 
c.JSON(422, gin.H{"errors" : err}) 

我的輸出:

{"errors":"[{}]"} 

回答

1

error type是一個接口,它必須實現一個將錯誤消息作爲字符串返回的方法Error()。這是在這裏定義的:https://golang.org/pkg/builtin/#errorerror類型爲接口的原因是爲了允許可以類型轉換的error類型檢索更詳細的信息。

fmt.Printlnlog.Println這樣的函數會自動解析error類型以顯示來自Error()的消息,但是JSON庫不會。解決此問題的最簡單方法是將[]error中的錯誤消息轉換爲[]string並對其進行編碼。

下面是一些示例代碼做一個for循環。

errs := person.Validate() 
strErrors := make([]string, len(errs)) 

for i, err := range errs { 
    strErrors[i] = err.Error() 
} 

c.JSON(422, gin.H{"errors" : strErrors}) 
0

error類型是具有單個Error()方法的接口,但它不是特殊的json包(Error()方法不被調用就可以了)。

但是,error值可能包含靜態類型的值,這些值可能是很好的編碼,或者他們可以通過執行json.Marshaler來定義自己的編組邏輯。通過調用Error()方法簡單地將error轉換爲string意味着我們不尊重自定義編組邏輯。

所以我建議建立我們自己的錯誤切片類型上,我們可以實現這應該是我們的編組邏輯:

  • 檢查,如果誤差值實現json.Marshaler,如果是的話,讓它元帥本身
  • 否則作爲備用的情況下調用error.Error()以「獲得」 string它可以很容易地封

這怎麼可能是這樣的:

type JSONErrs []error 

func (je JSONErrs) MarshalJSON() ([]byte, error) { 
    res := make([]interface{}, len(je)) 
    for i, e := range je { 
     if _, ok := e.(json.Marshaler); ok { 
      res[i] = e // e knows how to marshal itself 
     } else { 
      res[i] = e.Error() // Fallback to the error string 
     } 
    } 
    return json.Marshal(res) 
} 

而且這是你如何使用它:

err := person.Validate() 
c.JSON(422, gin.H{"errors" : JSONErrs(err)}) 

讓我們來測試我們的JSONErrs。我們還用它實現自定義編組邏輯自定義錯誤類型:

type MyErr struct{ line int } 

func (me MyErr) Error() string { return "Invalid input!" } 

func (me MyErr) MarshalJSON() ([]byte, error) { 
    return json.Marshal(
     struct { 
      Type, Error string 
      AtLine  int 
     }{"MyErr", me.Error(), me.line}) 
} 

並測試代碼:

errs := []error{ 
    errors.New("first"), 
    errors.New("second"), 
    MyErr{16}, 
} 

data, err := json.Marshal(JSONErrs(errs)) 
fmt.Println(string(data), err) 

輸出(嘗試在Go Playground):

["first","second",{"Type":"MyErr","Error":"Invalid input!","AtLine":16}] <nil>