2016-09-05 10 views
3

現在、Golangを使用してAPIを設定しています。私はサインアップルートを作っているので、すべてが私のSignupModelに入っていることを確認する必要があります。だから今のところ私は非常に条件を使用しています。私はより効率的/エレガントなソリューションがなければならないと確信していますが、どういうわけかそれらを見つけることができません。助けを事前にPOSTパラメータを確認するより良い方法はありますか?

// My SignupModel 
type SignupModel struct { 
    ID  string `json:"id"` 
    Username string `json:"username"` 
    FbToken string `json:"fbtoken"` 
    Email  string `json:"email"` 
    Firstname string `json:"firstname"` 
    Lastname string `json:"lastname"` 
    Picture string `json:"picture"` 
} 

// This is the condition I'm using inside my route (I know it's terrible) 
if signup.ID != "" && signup.Username != "" && signup.FbToken == "" && signup.Email == "" && signup.Firstname == "" && signup.Lastname == "" && signup.Picture == "" {   
    json.NewEncoder(w).Encode(signup) 
} else { 
    statusResponse := StatusResponse{Status: "Something went wrong", StatusCode: 401} 
    json.NewEncoder(w).Encode(statusResponse) 
} 

ありがとう:ここ

は、コードスニペットです。

+1

コードは正常です。それはひどいことではありません。 – Uvelichitel

答えて

4

あなたは、構造体のすべてのフィールドをチェックするためにリフレクションを使用する一般的なヘルパー関数(reflectパッケージ)を作成することができます。

それを使用して
func check(s interface{}) error { 
    v := reflect.ValueOf(s) 
    for i := v.NumField() - 1; i >= 0; i-- { 
     if v.Field(i).Interface() == "" { 
      return fmt.Errorf("Field %s is empty!", v.Type().Field(i).Name) 
     } 
    } 
    return nil 
} 

fmt.Println(check(SignupModel{"a", "b", "c", "d", "e", "f", "g"})) 
fmt.Println(check(SignupModel{})) 

出力を(Go Playground上でそれを試してみてください):

<nil> 
Field Picture is empty! 

Improv ements:

上記check()機能だけではなくSignupModelのために、すべてのタイプのために動作しますが、現在はそれが唯一のIS-string型のフィールドを処理します-as。他のフィールドタイプをサポートしたい場合は、それを改善することができます。

これは、他の型のフィールドも扱う改良されたバージョンです。また、渡された値が構造体へのポインタ(単純に逆参照する)であるかどうかを処理します。

func check(s interface{}) error { 
    v := reflect.Indirect(reflect.ValueOf(s)) 
    if v.Kind() != reflect.Struct { 
     return fmt.Errorf("Not struct!") 
    } 
    v2 := reflect.Zero(v.Type()) 
    for i := v.NumField() - 1; i >= 0; i-- { 
     if v.Field(i).Interface() == v2.Field(i).Interface() { 
      return fmt.Errorf("Field %s is empty!", v.Type().Field(i).Name) 
     } 
    } 
    return nil 
} 

テストそれ::

fmt.Println(check(&struct{ I int }{1})) 
fmt.Println(check(struct{ I int }{})) 
fmt.Println(check(struct { I int; S string }{1, "a"})) 
fmt.Println(check(&struct { I int; S string }{})) 
fmt.Println(check("I'm a string")) 

出力(Go Playground上でそれを試してみてください):

<nil> 
Field I is empty! 
<nil> 
Field S is empty! 
Not struct! 

決勝ノート非struct値が渡された場合、それはエラーを返します:

上記の溶液直接コード(短縮しようとしているコード)よりも常に遅い反射を使用します。ベンチマーク - しかし、我々はHTTP POSTリクエストの話をしていることから、パフォーマンスの違いは、(このcheck()関数は半分をとりながら、HTTP POSTリクエストはミリ秒数百を取ることができるよう、あなたのSignupModel型の値と呼ばれるマイクロは無視できます)。ユニークcheckXX()ヘルパー関数、それぞれに1つずつ生成されます:あなたのコードとその柔軟性の速さをミックスしたいと思います場合は、1つのオプションジェネレータを作成することです

Generating codego generate、ブログ記事を読んで) (直接フィールド値の比較を使用して)リフレクションなしで動作する別個の構造体型。

+1

驚くほど詳細な答え。大変ありがとうございます! – MEGADEVOPS

+0

リフレクションを使用するコードは、元のアプローチのように、リフレクションを使用しないコードよりもはるかに遅いことに注意してください。 – cd1

+0

@ cd1はい、そうです。しかし、すでにHTTP POST要求について話しているので、パフォーマンスの差はごくわずかです。 – icza

関連する問題