2016-12-16 3 views
1

Мне нужно создать обработчик HTTP для REST API.Как написать общий обработчик в Go?

Этот API REST имеет много разных объектов, которые хранятся в базе данных (MongoDB в моем случае).

В настоящее время мне нужно написать один обработчик за действие на объект.

Я хотел бы найти способ, как это возможно с Дженерики написать общий обработчик, который может обрабатывать определенное действие, но для любого вида объекта (как в основном это просто CRUD в большинстве случае)

Как я могу сделать это ?

Вот примеры обработчиков я хотел бы превратиться в родовое один:

func IngredientIndex(w http.ResponseWriter, r *http.Request) { 
    w.Header().Set("Content-Type", "application/json; charset=UTF-8") 
    db := r.Context().Value("Database").(*mgo.Database) 
    ingredients := []data.Ingredient{} 
    err := db.C("ingredients").Find(bson.M{}).All(&ingredients) 
    if err != nil { 
     panic(err) 
    } 
    json.NewEncoder(w).Encode(ingredients) 
} 

func IngredientGet(w http.ResponseWriter, r *http.Request) { 
    w.Header().Set("Content-Type", "application/json; charset=UTF-8") 
    vars := mux.Vars(r) 
    logger := r.Context().Value("Logger").(zap.Logger) 
    db := r.Context().Value("Database").(*mgo.Database) 
    ingredient := data.Ingredient{} 
    err := db.C("ingredients").Find(bson.M{"_id": bson.ObjectIdHex(vars["id"])}).One(&ingredient) 
    if err != nil { 
     w.WriteHeader(404) 
     logger.Info("Fail to find entity", zap.Error(err)) 
    } else { 
     json.NewEncoder(w).Encode(ingredient) 
    } 
} 

В принципе я бы нужен обработчик, как это (Это мое предварительное, что не работает):

func ObjectIndex(collection string, container interface{}) func(http.ResponseWriter, *http.Request) { 
    return func(w http.ResponseWriter, r *http.Request) { 
     w.Header().Set("Content-Type", "application/json; charset=UTF-8") 
     db := r.Context().Value("Database").(*mgo.Database) 
     objects := container 
     err := db.C(collection).Find(bson.M{}).All(&objects) 
     if err != nil { 
      panic(err) 
     } 
     json.NewEncoder(w).Encode(objects) 
    } 

Как я могу это сделать?

+0

Вы сказали: «В настоящее время мне нужно написать обработчик за действие на объект». Это то, что я использую 'go generate' for. Вам не нужны дженерики! – eduncan911

+1

Это хорошая практика? Потому что в основном, делая это, я все равно буду иметь дублированный код во всем мире, который будет сложнее поддерживать, чем общий код, обрабатывающий большинство случаев. – Kedare

ответ

3

Используйте отражают пакет для создания нового контейнера при каждом вызове:

func ObjectIndex(collection string, container interface{}) func(http.ResponseWriter, *http.Request) { 
    t := reflect.TypeOf(container) 
    return func(w http.ResponseWriter, r *http.Request) { 
    w.Header().Set("Content-Type", "application/json; charset=UTF-8") 
    db := r.Context().Value("Database").(*mgo.Database) 
    objects := reflect.New(t).Interface() 
    err := db.C(collection).Find(bson.M{}).All(objects) 
    if err != nil { 
     panic(err) 
    } 
    json.NewEncoder(w).Encode(objects) 
} 

Зов это следующим образом:

h := ObjectIndex("ingredients", data.Ingredient{}) 

при условии, что data.Indgredient тип среза.

+0

Удивительно, это именно то, что я искал, спасибо! :) – Kedare