From 5140b9eca0923966f0afd7f51b4ef467bcb47f73 Mon Sep 17 00:00:00 2001 From: alldroll Date: Fri, 22 Nov 2019 14:19:10 +0000 Subject: [PATCH] Slightly cleanup code --- internal/http/utils.go | 72 ++++++++++++++++++++ internal/spellchecker/api/app.go | 17 ----- internal/spellchecker/api/predict_handler.go | 21 ++++-- internal/suggest/api/autocomplete_handler.go | 13 ++-- internal/suggest/api/dict_handler.go | 6 +- internal/suggest/api/reindex_handler.go | 6 +- internal/suggest/api/suggest_handler.go | 47 +++++++------ 7 files changed, 132 insertions(+), 50 deletions(-) create mode 100644 internal/http/utils.go diff --git a/internal/http/utils.go b/internal/http/utils.go new file mode 100644 index 0000000..b004b51 --- /dev/null +++ b/internal/http/utils.go @@ -0,0 +1,72 @@ +package http + +import ( + "errors" + "net/http" + "strconv" +) + +// FormTopKValue returns the first value for the named component of the query and +// validates it with topK value restrictions +func FormTopKValue(r *http.Request, field string, defaultVal int) (int, error) { + val, err := FormIntValue(r, field, defaultVal) + + if err != nil { + return 0, err + } + + if val < 0 { + return 0, errors.New("topK should be positive integer") + } + + return val, nil +} + +// FormSimilarityValue returns the first value for the named component of the query and +// validates it with similarity value restrictions +func FormSimilarityValue(r *http.Request, field string, defaultVal float64) (float64, error) { + val, err := FormFloatValue(r, field, defaultVal) + + if err != nil { + return 0, err + } + + if val < 0 || val > 1 { + return 0, errors.New("similarity should be in [0, 1] range") + } + + return val, nil +} + +func FormIntValue(r *http.Request, field string, defaultVal int) (int, error) { + val := r.FormValue(field) + + if val == "" { + return defaultVal, nil + } + + i64, err := strconv.ParseInt(val, 10, 0) + + if err != nil { + return 0, err + } + + return int(i64), nil +} + +func FormFloatValue(r *http.Request, field string, defaultVal float64) (float64, error) { + val := r.FormValue(field) + + if val == "" { + return defaultVal, nil + } + + f64, err := strconv.ParseFloat(val, 64) + + if err != nil { + return 0, err + } + + return f64, nil +} + diff --git a/internal/spellchecker/api/app.go b/internal/spellchecker/api/app.go index 1096998..d57ba58 100644 --- a/internal/spellchecker/api/app.go +++ b/internal/spellchecker/api/app.go @@ -71,23 +71,6 @@ func (a App) Run() error { return httpServer.Run(ctx) } -// configureService tries to retrieve index descriptions and to setup the suggest service -func (a App) configureService(suggestService *suggest.Service) error { - description, err := suggest.ReadConfigs(a.config.ConfigPath) - - if err != nil { - return err - } - - for _, config := range description { - if err := suggestService.AddIndexByDescription(config); err != nil { - return err - } - } - - return nil -} - // listenToSystemSignals handles OS signals func (a App) listenToSystemSignals(cancelFn context.CancelFunc) { signalChan := make(chan os.Signal, 1) diff --git a/internal/spellchecker/api/predict_handler.go b/internal/spellchecker/api/predict_handler.go index 6ba512c..8c04fb7 100644 --- a/internal/spellchecker/api/predict_handler.go +++ b/internal/spellchecker/api/predict_handler.go @@ -2,9 +2,10 @@ package api import ( "encoding/json" + _ "github.com/suggest-go/suggest/internal/http" + httputil "github.com/suggest-go/suggest/internal/http" "github.com/suggest-go/suggest/pkg/spellchecker" "net/http" - "strconv" "github.com/gorilla/mux" ) @@ -19,17 +20,23 @@ func (h *predictHandler) handle(w http.ResponseWriter, r *http.Request) { var ( vars = mux.Vars(r) query = vars["query"] - k = r.FormValue("topK") ) - i64, err := strconv.ParseInt(k, 10, 0) + topK, err := httputil.FormTopKValue(r, "topK", 5) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } - resultItems, err := h.spellchecker.Predict(query, int(i64), 0.3) + similarity, err := httputil.FormSimilarityValue(r, "similarity", 0.5) + + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + resultItems, err := h.spellchecker.Predict(query, topK, similarity) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -44,5 +51,9 @@ func (h *predictHandler) handle(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - w.Write(data) + + if _, err := w.Write(data); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } diff --git a/internal/suggest/api/autocomplete_handler.go b/internal/suggest/api/autocomplete_handler.go index 296d167..b8626db 100644 --- a/internal/suggest/api/autocomplete_handler.go +++ b/internal/suggest/api/autocomplete_handler.go @@ -2,8 +2,8 @@ package api import ( "encoding/json" + httputil "github.com/suggest-go/suggest/internal/http" "net/http" - "strconv" "github.com/gorilla/mux" "github.com/suggest-go/suggest/pkg/suggest" @@ -20,17 +20,16 @@ func (h *autocompleteHandler) handle(w http.ResponseWriter, r *http.Request) { vars = mux.Vars(r) dict = vars["dict"] query = vars["query"] - k = r.FormValue("topK") ) - i64, err := strconv.ParseInt(k, 10, 0) + topK, err := httputil.FormTopKValue(r, "topK", defaultTopK) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } - resultItems, err := h.suggestService.Autocomplete(dict, query, int(i64)) + resultItems, err := h.suggestService.Autocomplete(dict, query, topK) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -45,5 +44,9 @@ func (h *autocompleteHandler) handle(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - w.Write(data) + + if _, err := w.Write(data); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } diff --git a/internal/suggest/api/dict_handler.go b/internal/suggest/api/dict_handler.go index 3c0aa51..d408db4 100644 --- a/internal/suggest/api/dict_handler.go +++ b/internal/suggest/api/dict_handler.go @@ -22,5 +22,9 @@ func (h *dictionaryHandler) handle(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - w.Write(data) + + if _, err := w.Write(data); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } diff --git a/internal/suggest/api/reindex_handler.go b/internal/suggest/api/reindex_handler.go index 47a04a9..7be3121 100644 --- a/internal/suggest/api/reindex_handler.go +++ b/internal/suggest/api/reindex_handler.go @@ -15,5 +15,9 @@ func (h *reindexHandler) handle(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "text/plain") - w.Write([]byte("OK")) + + if _, err := w.Write([]byte("OK")); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } diff --git a/internal/suggest/api/suggest_handler.go b/internal/suggest/api/suggest_handler.go index fac370a..986466b 100644 --- a/internal/suggest/api/suggest_handler.go +++ b/internal/suggest/api/suggest_handler.go @@ -3,12 +3,11 @@ package api import ( "encoding/json" "errors" - "net/http" - "strconv" - "github.com/gorilla/mux" + httputil "github.com/suggest-go/suggest/internal/http" "github.com/suggest-go/suggest/pkg/metric" "github.com/suggest-go/suggest/pkg/suggest" + "net/http" ) const ( @@ -17,6 +16,9 @@ const ( dice = "Dice" exact = "Exact" overlap = "Overlap" + + defaultSimilarity = 0.5 + defaultTopK = 5 ) var metrics map[string]metric.Metric @@ -41,19 +43,9 @@ func (h *suggestHandler) handle(w http.ResponseWriter, r *http.Request) { var ( vars = mux.Vars(r) dict = vars["dict"] - query = vars["query"] - metricName = r.FormValue("metric") - similarity = r.FormValue("similarity") - k = r.FormValue("topK") ) - i64, err := strconv.ParseInt(k, 10, 0) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - searchConf, err := buildSearchConfig(query, metricName, similarity, int(i64)) + searchConf, err := buildSearchConfig(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) @@ -76,21 +68,34 @@ func (h *suggestHandler) handle(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - w.Write(data) + + if _, err := w.Write(data); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } // buildSearchConfig builds a search config for the given list of parameters -func buildSearchConfig(query, metricName, sim string, k int) (suggest.SearchConfig, error) { - if _, ok := metrics[metricName]; !ok { - return suggest.SearchConfig{}, errors.New("Metric not found") +func buildSearchConfig(r *http.Request) (suggest.SearchConfig, error) { + vars := mux.Vars(r) + topK, err := httputil.FormTopKValue(r, "topK", defaultTopK) + + if err != nil { + return suggest.SearchConfig{}, err + } + + metricName := r.FormValue("metric") + m, ok := metrics[metricName] + + if !ok { + return suggest.SearchConfig{}, errors.New("metric is not found") } - metric := metrics[metricName] - similarity, err := strconv.ParseFloat(sim, 64) + similarity, err := httputil.FormSimilarityValue(r, "similarity", defaultSimilarity) if err != nil { return suggest.SearchConfig{}, err } - return suggest.NewSearchConfig(query, k, metric, similarity) + return suggest.NewSearchConfig(vars["query"], topK, m, similarity) }