dangogh closed pull request #1860: normalize url query parameters handling and 
where and orderby clause construction
URL: https://github.com/apache/incubator-trafficcontrol/pull/1860
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/lib/go-tc/alerts.go b/lib/go-tc/alerts.go
index 5dd4b082e1..52066b42e0 100644
--- a/lib/go-tc/alerts.go
+++ b/lib/go-tc/alerts.go
@@ -75,4 +75,18 @@ func GetHandleErrorsFunc(w http.ResponseWriter, r 
*http.Request) func(status int
        }
 }
 
+func HandleErrorsWithType(errs []error, errType ApiErrorType, handleErrs 
func(status int, errs ...error)) {
+               switch errType {
+               case SystemError:
+                       handleErrs(http.StatusInternalServerError, errs...)
+               case DataConflictError:
+                       handleErrs(http.StatusBadRequest, errs...)
+               case DataMissingError:
+                       handleErrs(http.StatusNotFound, errs...)
+               default:
+                       log.Errorf("received unknown ApiErrorType from read: 
%s\n", errType.String())
+                       handleErrs(http.StatusInternalServerError, errs...)
+               }
+}
+
 var StatusKey = "status"
\ No newline at end of file
diff --git a/traffic_ops/traffic_ops_golang/api/shared_handlers.go 
b/traffic_ops/traffic_ops_golang/api/shared_handlers.go
index ce5e5d7161..58fe3b482e 100644
--- a/traffic_ops/traffic_ops_golang/api/shared_handlers.go
+++ b/traffic_ops/traffic_ops_golang/api/shared_handlers.go
@@ -35,23 +35,57 @@ import (
        "github.com/jmoiron/sqlx"
 )
 
-type PathParams map[string]string
-
 const PathParamsKey = "pathParams"
 
-func GetPathParams(ctx context.Context) (PathParams, error) {
+func GetPathParams(ctx context.Context) (map[string]string, error) {
        val := ctx.Value(PathParamsKey)
        if val != nil {
                switch v := val.(type) {
-               case PathParams:
+               case map[string]string:
                        return v, nil
                default:
-                       return nil, fmt.Errorf("PathParams found with bad type: 
%T", v)
+                       return nil, fmt.Errorf("path parameters found with bad 
type: %T", v)
                }
        }
        return nil, errors.New("no PathParams found in Context")
 }
 
+func IsInt(s string) error {
+       _, err := strconv.Atoi(s)
+       if err != nil {
+               err = errors.New("cannot parse to integer")
+       }
+       return err
+}
+
+func IsBool(s string) error {
+       _, err := strconv.ParseBool(s)
+       if err != nil {
+               err = errors.New("cannot parse to boolean")
+       }
+       return err
+}
+
+func GetCombinedParams(r *http.Request) (map[string]string, error) {
+       combinedParams := make(map[string]string)
+       q := r.URL.Query()
+       for k, v := range q {
+               combinedParams[k] = v[0] //we take the first value and do not 
support multiple keys in query parameters
+       }
+
+       ctx := r.Context()
+       pathParams, err := GetPathParams(ctx)
+       if err != nil {
+               return combinedParams, fmt.Errorf("no path parameters: %s", err)
+       }
+       //path parameters will overwrite query parameters
+       for k, v := range pathParams {
+               combinedParams[k] = v
+       }
+
+       return combinedParams, nil
+}
+
 //decodes and validates a pointer to a struct implementing the Validator 
interface
 //      we lose the ability to unmarshal the struct if a struct implementing 
the interface is passed in,
 //      because when when it is de-referenced it is a pointer to an interface. 
A new copy is created so that
@@ -80,23 +114,12 @@ func ReadHandler(typeRef Reader, db *sqlx.DB) 
http.HandlerFunc {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
                ctx := r.Context()
-               pathParams, err := GetPathParams(ctx)
-               if err != nil {
-                       handleErrs(http.StatusInternalServerError, err)
-                       return
-               }
 
                // Load the PathParams into the query parameters for pass 
through
-               q := r.URL.Query()
-               for k, v := range pathParams {
-                       if k == `id` {
-                               if _, err := strconv.Atoi(v); err != nil {
-                                       log.Errorf("Expected {id} to be an 
integer: %s", v)
-                                       handleErrs(http.StatusNotFound, 
errors.New("Resource not found.")) //matches perl response
-                                       return
-                               }
-                       }
-                       q.Set(k, v)
+               params, err := GetCombinedParams(r)
+               if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
+                       handleErrs(http.StatusInternalServerError, err)
                }
 
                user, err := auth.GetCurrentUser(ctx)
@@ -105,19 +128,9 @@ func ReadHandler(typeRef Reader, db *sqlx.DB) 
http.HandlerFunc {
                        handleErrs(http.StatusInternalServerError, err)
                }
 
-               results, err, errType := typeRef.Read(db, q, *user)
-               if err != nil {
-                       switch errType {
-                       case tc.SystemError:
-                               handleErrs(http.StatusInternalServerError, err)
-                       case tc.DataConflictError:
-                               handleErrs(http.StatusBadRequest, err)
-                       case tc.DataMissingError:
-                               handleErrs(http.StatusNotFound, err)
-                       default:
-                               log.Errorf("received unknown ApiErrorType from 
read: %s\n", errType.String())
-                               handleErrs(http.StatusInternalServerError, err)
-                       }
+               results, errs, errType := typeRef.Read(db, params, *user)
+               if len(errs) > 0 {
+                       tc.HandleErrorsWithType(errs, errType, handleErrs)
                        return
                }
                resp := struct {
@@ -184,17 +197,7 @@ func UpdateHandler(typeRef Updater, db *sqlx.DB) 
http.HandlerFunc {
                //run the update and handle any error
                err, errType := u.Update(db, *user)
                if err != nil {
-                       switch errType {
-                       case tc.SystemError:
-                               handleErrs(http.StatusInternalServerError, err)
-                       case tc.DataConflictError:
-                               handleErrs(http.StatusBadRequest, err)
-                       case tc.DataMissingError:
-                               handleErrs(http.StatusNotFound, err)
-                       default:
-                               log.Errorf("received unknown ApiErrorType from 
update: %s, updating: %s id: %d\n", errType.String(), u.GetType(), u.GetID())
-                               handleErrs(http.StatusInternalServerError, err)
-                       }
+                       tc.HandleErrorsWithType([]error{err}, errType, 
handleErrs)
                        return
                }
                //auditing here
@@ -250,17 +253,7 @@ func DeleteHandler(typeRef Deleter, db *sqlx.DB) 
http.HandlerFunc {
                log.Debugf("calling delete on object: %++v", d) //should have 
id set now
                err, errType := d.Delete(db, *user)
                if err != nil {
-                       switch errType {
-                       case tc.SystemError:
-                               handleErrs(http.StatusInternalServerError, err)
-                       case tc.DataConflictError:
-                               handleErrs(http.StatusBadRequest, err)
-                       case tc.DataMissingError:
-                               handleErrs(http.StatusNotFound, err)
-                       default:
-                               log.Errorf("received unknown ApiErrorType from 
delete: %s, deleting: %s id: %d\n", errType.String(), d.GetType(), d.GetID())
-                               handleErrs(http.StatusInternalServerError, err)
-                       }
+                       tc.HandleErrorsWithType([]error{err}, errType, 
handleErrs)
                        return
                }
                //audit here
@@ -312,17 +305,7 @@ func CreateHandler(typeRef Inserter, db *sqlx.DB) 
http.HandlerFunc {
 
                err, errType := i.Insert(db, *user)
                if err != nil {
-                       switch errType {
-                       case tc.SystemError:
-                               handleErrs(http.StatusInternalServerError, err)
-                       case tc.DataConflictError:
-                               handleErrs(http.StatusBadRequest, err)
-                       case tc.DataMissingError:
-                               handleErrs(http.StatusNotFound, err)
-                       default:
-                               log.Errorf("received unknown ApiErrorType from 
insert: %s, inserting: %s id: %d\n", errType.String(), i.GetType(), i.GetID())
-                               handleErrs(http.StatusInternalServerError, err)
-                       }
+                       tc.HandleErrorsWithType([]error{err}, errType, 
handleErrs)
                        return
                }
 
diff --git a/traffic_ops/traffic_ops_golang/api/shared_handlers_test.go 
b/traffic_ops/traffic_ops_golang/api/shared_handlers_test.go
index 312bebfb25..d167d6ddef 100644
--- a/traffic_ops/traffic_ops_golang/api/shared_handlers_test.go
+++ b/traffic_ops/traffic_ops_golang/api/shared_handlers_test.go
@@ -32,8 +32,6 @@ import (
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
        "github.com/jmoiron/sqlx"
 
-       "net/url"
-
        sqlmock "gopkg.in/DATA-DOG/go-sqlmock.v1"
 )
 
@@ -74,7 +72,7 @@ func (i *tester) SetID(newID int) {
 }
 
 //Reader interface functions
-func (i *tester) Read(db *sqlx.DB, v url.Values, user auth.CurrentUser) 
([]interface{}, error, tc.ApiErrorType) {
+func (i *tester) Read(db *sqlx.DB, v map[string]string, user auth.CurrentUser) 
([]interface{}, []error, tc.ApiErrorType) {
        return []interface{}{tester{ID: 1}}, nil, tc.NoError
 }
 
@@ -152,7 +150,7 @@ func TestReadHandler(t *testing.T) {
        ctx := r.Context()
        ctx = context.WithValue(ctx, auth.CurrentUserKey,
                auth.CurrentUser{UserName: "username", ID: 1, PrivLevel: 
auth.PrivLevelAdmin})
-       ctx = context.WithValue(ctx, PathParamsKey, PathParams{"id": "1"})
+       ctx = context.WithValue(ctx, PathParamsKey, map[string]string{"id": 
"1"})
        // Add our context to the request
        r = r.WithContext(ctx)
 
@@ -187,7 +185,7 @@ func TestUpdateHandler(t *testing.T) {
        ctx := r.Context()
        ctx = context.WithValue(ctx, auth.CurrentUserKey,
                auth.CurrentUser{UserName: "username", ID: 1, PrivLevel: 
auth.PrivLevelAdmin})
-       ctx = context.WithValue(ctx, PathParamsKey, PathParams{"id": "1"})
+       ctx = context.WithValue(ctx, PathParamsKey, map[string]string{"id": 
"1"})
        // Add our context to the request
        r = r.WithContext(ctx)
 
@@ -226,7 +224,7 @@ func TestDeleteHandler(t *testing.T) {
        ctx := r.Context()
        ctx = context.WithValue(ctx, auth.CurrentUserKey,
                auth.CurrentUser{UserName: "username", ID: 1, PrivLevel: 
auth.PrivLevelAdmin})
-       ctx = context.WithValue(ctx, PathParamsKey, PathParams{"id": "1"})
+       ctx = context.WithValue(ctx, PathParamsKey, map[string]string{"id": 
"1"})
        // Add our context to the request
        r = r.WithContext(ctx)
 
diff --git a/traffic_ops/traffic_ops_golang/api/shared_interfaces.go 
b/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
index 7c4d0bddb9..7d51ce10ae 100644
--- a/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
+++ b/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
@@ -20,8 +20,6 @@ package api
  */
 
 import (
-       "net/url"
-
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
        "github.com/jmoiron/sqlx"
@@ -61,5 +59,5 @@ type Tenantable interface {
 }
 
 type Reader interface {
-       Read(db *sqlx.DB, v url.Values, user auth.CurrentUser) ([]interface{}, 
error, tc.ApiErrorType)
+       Read(db *sqlx.DB, parameters map[string]string, user auth.CurrentUser) 
([]interface{}, []error, tc.ApiErrorType)
 }
diff --git a/traffic_ops/traffic_ops_golang/asns.go 
b/traffic_ops/traffic_ops_golang/asns.go
index 8d0ea23e95..86a2fa77ba 100644
--- a/traffic_ops/traffic_ops_golang/asns.go
+++ b/traffic_ops/traffic_ops_golang/asns.go
@@ -23,8 +23,8 @@ import (
        "encoding/json"
        "fmt"
        "net/http"
-       "net/url"
 
+       "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
@@ -39,21 +39,15 @@ func ASNsHandler(db *sqlx.DB) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-               ctx := r.Context()
-               pathParams, err := api.GetPathParams(ctx)
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
-                       return
                }
 
-               // Load the PathParams into the query parameters for pass 
through
-               q := r.URL.Query()
-               for k, v := range pathParams {
-                       q.Set(k, v)
-               }
-               resp, err := getASNsResponse(q, db)
-               if err != nil {
-                       handleErrs(http.StatusInternalServerError, err)
+               resp, errs, errType := getASNsResponse(params, db)
+               if len(errs) > 0 {
+                       tc.HandleErrorsWithType(errs, errType, handleErrs)
                        return
                }
 
@@ -68,35 +62,40 @@ func ASNsHandler(db *sqlx.DB) http.HandlerFunc {
        }
 }
 
-func getASNsResponse(q url.Values, db *sqlx.DB) (*tc.ASNsResponse, error) {
-       asns, err := getASNs(q, db)
-       if err != nil {
-               return nil, fmt.Errorf("getting asns response: %v", err)
+func getASNsResponse(parameters map[string]string, db *sqlx.DB) 
(*tc.ASNsResponse, []error, tc.ApiErrorType) {
+       asns, errs, errType := getASNs(parameters, db)
+       if len(errs) > 0 {
+               return nil, errs, errType
        }
 
        resp := tc.ASNsResponse{
                Response: asns,
        }
-       return &resp, nil
+       return &resp, nil, tc.NoError
 }
 
-func getASNs(v url.Values, db *sqlx.DB) ([]tc.ASN, error) {
+func getASNs(parameters map[string]string, db *sqlx.DB) ([]tc.ASN, []error, 
tc.ApiErrorType) {
        var rows *sqlx.Rows
        var err error
 
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToQueryCols := map[string]string{
-               "asn":        "a.asn",
-               "id":         "a.id",
-               "cachegroup": "cg.id",
+       queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+               "asn":        dbhelpers.WhereColumnInfo{"a.asn", api.IsInt},
+               "id":         dbhelpers.WhereColumnInfo{"a.id", api.IsInt},
+               "cachegroup": dbhelpers.WhereColumnInfo{"cg.id", api.IsInt},
        }
 
-       query, queryValues := dbhelpers.BuildQuery(v, selectASNsQuery(), 
queryParamsToQueryCols)
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(parameters, queryParamsToQueryCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
+       }
+       query := selectASNsQuery() + where + orderBy
+       log.Debugln("Query is ", query)
 
        rows, err = db.NamedQuery(query, queryValues)
        if err != nil {
-               return nil, err
+               return nil, []error{err}, tc.SystemError
        }
        defer rows.Close()
 
@@ -104,11 +103,11 @@ func getASNs(v url.Values, db *sqlx.DB) ([]tc.ASN, error) 
{
        for rows.Next() {
                var s tc.ASN
                if err = rows.StructScan(&s); err != nil {
-                       return nil, fmt.Errorf("getting ASNs: %v", err)
+                       return nil, []error{fmt.Errorf("getting ASNs: %v", 
err)}, tc.SystemError
                }
                ASNs = append(ASNs, s)
        }
-       return ASNs, nil
+       return ASNs, nil, tc.NoError
 }
 
 func selectASNsQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/asns_test.go 
b/traffic_ops/traffic_ops_golang/asns_test.go
index 94b8950a18..64101c0dd2 100644
--- a/traffic_ops/traffic_ops_golang/asns_test.go
+++ b/traffic_ops/traffic_ops_golang/asns_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-       "net/url"
        "testing"
        "time"
 
@@ -72,12 +71,11 @@ func TestGetASNs(t *testing.T) {
                )
        }
        mock.ExpectQuery("SELECT").WillReturnRows(rows)
-       v := url.Values{}
-       v.Set("dsId", "1")
+       v := map[string]string{"dsId": "1"}
 
-       servers, err := getASNs(v, db)
-       if err != nil {
-               t.Errorf("getASNs expected: nil error, actual: %v", err)
+       servers, errs, errType := getASNs(v, db)
+       if len(errs) > 0 {
+               t.Errorf("getASNs expected: no errors, actual: %v with type 
%s", errs, errType.String())
        }
 
        if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/cdn/cdns.go 
b/traffic_ops/traffic_ops_golang/cdn/cdns.go
index dd5265430f..ca02d09395 100644
--- a/traffic_ops/traffic_ops_golang/cdn/cdns.go
+++ b/traffic_ops/traffic_ops_golang/cdn/cdns.go
@@ -22,11 +22,11 @@ package cdn
 import (
        "errors"
        "fmt"
-       "net/url"
 
        "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
 
+       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
        "github.com/jmoiron/sqlx"
@@ -71,25 +71,29 @@ func (cdn *TOCDN) Validate(db *sqlx.DB) []error {
        return errs
 }
 
-func (cdn *TOCDN) Read(db *sqlx.DB, v url.Values, user auth.CurrentUser) 
([]interface{}, error, tc.ApiErrorType) {
+func (cdn *TOCDN) Read(db *sqlx.DB, parameters map[string]string, user 
auth.CurrentUser) ([]interface{}, []error, tc.ApiErrorType) {
        var rows *sqlx.Rows
-       var err error
 
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToQueryCols := map[string]string{
-               "domainName":    "domain_name",
-               "dnssecEnabled": "dnssec_enabled",
-               "id":            "id",
-               "name":          "name",
+       queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+               "domainName":    dbhelpers.WhereColumnInfo{"domain_name", nil},
+               "dnssecEnabled": dbhelpers.WhereColumnInfo{"dnssec_enabled", 
nil},
+               "id":            dbhelpers.WhereColumnInfo{"id", api.IsInt},
+               "name":          dbhelpers.WhereColumnInfo{"name", nil},
+       }
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(parameters, queryParamsToQueryCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
        }
 
-       query, queryValues := dbhelpers.BuildQuery(v, selectCDNsQuery(), 
queryParamsToQueryCols)
+       query := selectCDNsQuery() + where + orderBy
+       log.Debugln("Query is ", query)
 
-       rows, err = db.NamedQuery(query, queryValues)
+       rows, err := db.NamedQuery(query, queryValues)
        if err != nil {
                log.Errorf("Error querying CDNs: %v", err)
-               return nil, tc.DBError, tc.SystemError
+               return nil, []error{tc.DBError}, tc.SystemError
        }
        defer rows.Close()
 
@@ -98,12 +102,12 @@ func (cdn *TOCDN) Read(db *sqlx.DB, v url.Values, user 
auth.CurrentUser) ([]inte
                var s tc.CDN
                if err = rows.StructScan(&s); err != nil {
                        log.Errorf("error parsing CDN rows: %v", err)
-                       return nil, tc.DBError, tc.SystemError
+                       return nil, []error{tc.DBError}, tc.SystemError
                }
                CDNs = append(CDNs, s)
        }
 
-       return CDNs, nil, tc.NoError
+       return CDNs, []error{}, tc.NoError
 }
 
 func selectCDNsQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/cdn/cdns_test.go 
b/traffic_ops/traffic_ops_golang/cdn/cdns_test.go
index f8522babee..ff60aae1b1 100644
--- a/traffic_ops/traffic_ops_golang/cdn/cdns_test.go
+++ b/traffic_ops/traffic_ops_golang/cdn/cdns_test.go
@@ -20,7 +20,6 @@ package cdn
  */
 
 import (
-       "net/url"
        "testing"
        "time"
 
@@ -79,12 +78,11 @@ func TestReadCDNs(t *testing.T) {
                )
        }
        mock.ExpectQuery("SELECT").WillReturnRows(rows)
-       v := url.Values{}
-       v.Set("dsId", "1")
+       v := map[string]string{"dsId": "1"}
 
-       servers, err, _ := refType.Read(db, v, auth.CurrentUser{})
-       if err != nil {
-               t.Errorf("cdn.Read expected: nil error, actual: %v", err)
+       servers, errs, _ := refType.Read(db, v, auth.CurrentUser{})
+       if len(errs) > 0 {
+               t.Errorf("cdn.Read expected: no errors, actual: %v", errs)
        }
 
        if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go 
b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
index c5d9237f94..24f0f7ce79 100644
--- a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
+++ b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
@@ -21,7 +21,6 @@ package dbhelpers
 
 import (
        "errors"
-       "net/url"
        "strings"
 
        "github.com/apache/incubator-trafficcontrol/lib/go-log"
@@ -29,47 +28,74 @@ import (
        "github.com/lib/pq"
 )
 
-func BuildQuery(v url.Values, selectStmt string, queryParamsToSQLCols 
map[string]string) (string, map[string]interface{}) {
-       var sqlQuery string
+type WhereColumnInfo struct {
+       Column  string
+       Checker func(string) error
+}
+
+const baseWhere = "\nWHERE"
+const baseOrderBy = "\nORDER BY"
+
+func BuildWhereAndOrderBy(parameters map[string]string, queryParamsToSQLCols 
map[string]WhereColumnInfo) (string, string, map[string]interface{}, []error) {
+       whereClause := baseWhere
+       orderBy := baseOrderBy
        var criteria string
        var queryValues map[string]interface{}
-       sqlQuery = selectStmt
-       criteria, queryValues = 
parseCriteriaAndQueryValues(queryParamsToSQLCols, v)
+       var errs []error
+       criteria, queryValues, errs = 
parseCriteriaAndQueryValues(queryParamsToSQLCols, parameters)
 
        if len(queryValues) > 0 {
-               sqlQuery += "\nWHERE " + criteria
+               whereClause += " " + criteria
+       }
+       if len(errs) > 0 {
+               return "", "", queryValues, errs
        }
 
-       if orderby, ok := v["orderby"]; ok {
-               log.Debugln("orderby: ", orderby[0])
-               if col, ok := queryParamsToSQLCols[orderby[0]]; ok {
-                       log.Debugln("orderby column ", col)
-                       sqlQuery += "\nORDER BY " + col
+       if orderby, ok := parameters["orderby"]; ok {
+               log.Debugln("orderby: ", orderby)
+               if colInfo, ok := queryParamsToSQLCols[orderby]; ok {
+                       log.Debugln("orderby column ", colInfo)
+                       orderBy += " " + colInfo.Column
                } else {
-                       log.Debugln("Incorrect name for orderby: ", orderby[0])
+                       log.Debugln("Incorrect name for orderby: ", orderby)
                }
        }
-       log.Debugln("\n--\n" + sqlQuery)
-       return sqlQuery, queryValues
+       if whereClause == baseWhere {
+               whereClause = ""
+       }
+       if orderBy == baseOrderBy {
+               orderBy = ""
+       }
+       log.Debugf("\n--\n Where: %s \n Order By: %s", whereClause, orderBy)
+       return whereClause, orderBy, queryValues, errs
 }
 
-func parseCriteriaAndQueryValues(queryParamsToSQLCols map[string]string, v 
url.Values) (string, map[string]interface{}) {
+func parseCriteriaAndQueryValues(queryParamsToSQLCols 
map[string]WhereColumnInfo, parameters map[string]string) (string, 
map[string]interface{}, []error) {
        m := make(map[string]interface{})
        var criteria string
 
        var criteriaArgs []string
+       errs := []error{}
        queryValues := make(map[string]interface{})
-       for key, val := range queryParamsToSQLCols {
-               if urlValue, ok := v[key]; ok {
-                       m[key] = urlValue[0]
-                       criteria = val + "=:" + key
-                       criteriaArgs = append(criteriaArgs, criteria)
-                       queryValues[key] = urlValue[0]
+       for key, colInfo := range queryParamsToSQLCols {
+               if urlValue, ok := parameters[key]; ok {
+                       var err error
+                       if colInfo.Checker != nil {
+                               err = colInfo.Checker(urlValue)
+                       }
+                       if err != nil {
+                               errs = append(errs, errors.New(key+" 
"+err.Error()))
+                       } else {
+                               m[key] = urlValue
+                               criteria = colInfo.Column + "=:" + key
+                               criteriaArgs = append(criteriaArgs, criteria)
+                               queryValues[key] = urlValue
+                       }
                }
        }
        criteria = strings.Join(criteriaArgs, " AND ")
 
-       return criteria, queryValues
+       return criteria, queryValues, errs
 }
 
 //parses pq errors for uniqueness constraint violations
diff --git a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers_test.go 
b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers_test.go
index 6c4a57a0ea..4cc5729686 100644
--- a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers_test.go
+++ b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers_test.go
@@ -20,7 +20,6 @@ package dbhelpers
  */
 
 import (
-       "net/url"
        "strings"
        "testing"
        "unicode"
@@ -36,9 +35,7 @@ func stripAllWhitespace(s string) string {
 }
 
 func TestBuildQuery(t *testing.T) {
-       v := url.Values{}
-       v.Set("param1", "queryParamv1")
-       v.Set("param2", "queryParamv2")
+       v := map[string]string{"param1": "queryParamv1","param2": 
"queryParamv2"}
 
        selectStmt := `SELECT
        t.col1,
@@ -47,18 +44,18 @@ FROM table t
 `
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToSQLCols := map[string]string{
-               "param1": "t.col1",
-               "param2": "t.col2",
+       queryParamsToSQLCols := map[string]WhereColumnInfo{
+               "param1": WhereColumnInfo{"t.col1",nil},
+               "param2": WhereColumnInfo{"t.col2",nil},
        }
-       query, queryValues := BuildQuery(v, selectStmt, queryParamsToSQLCols)
-
+       where, orderBy, queryValues, _ := BuildWhereAndOrderBy(v, 
queryParamsToSQLCols)
+       query := selectStmt + where + orderBy
        actualQuery := stripAllWhitespace(query)
 
        if queryValues == nil {
                t.Errorf("expected: nil error, actual: %v", queryValues)
        }
-       expectedV1 := v.Get("param1")
+       expectedV1 := v["param1"]
        actualV1 := queryValues["param1"]
        if expectedV1 != actualV1 {
                t.Errorf("expected: %v error, actual: %v", expectedV1, actualV1)
@@ -68,7 +65,7 @@ FROM table t
                t.Errorf("expected: %v error, actual: %v", actualQuery, 
expectedV1)
        }
 
-       expectedV2 := v.Get("param2")
+       expectedV2 := v["param2"]
        if strings.Contains(actualQuery, expectedV2) {
                t.Errorf("expected: %v error, actual: %v", actualQuery, 
expectedV2)
        }
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/handlers.go 
b/traffic_ops/traffic_ops_golang/deliveryservice/handlers.go
index 6fd7323fa6..558487317a 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/handlers.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/handlers.go
@@ -23,8 +23,8 @@ import (
        "encoding/json"
        "fmt"
        "net/http"
-       "net/url"
 
+       "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
@@ -37,24 +37,15 @@ func Handler(db *sqlx.DB) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-               ctx := r.Context()
-               pathParams, err := api.GetPathParams(ctx)
+               // Load the the query and path params with path params 
overriding query params
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
-                       return
-               }
-
-               q := r.URL.Query()
-               for k, v := range pathParams {
-                       q.Set(k, v)
                }
 
-               resp, err := getDeliveryServicesResponse(q, db)
-
-               if err != nil {
-                       handleErrs(http.StatusInternalServerError, err)
-                       return
-               }
+               resp, errs, errType := getDeliveryServicesResponse(params, db)
+               tc.HandleErrorsWithType(errs, errType, handleErrs)
 
                respBts, err := json.Marshal(resp)
                if err != nil {
@@ -67,35 +58,39 @@ func Handler(db *sqlx.DB) http.HandlerFunc {
        }
 }
 
-func getDeliveryServicesResponse(q url.Values, db *sqlx.DB) 
(*tc.DeliveryServicesResponse, error) {
-       dses, err := getDeliveryServices(q, db)
-       if err != nil {
-               return nil, fmt.Errorf("getting DeliveryServices response: %v", 
err)
+func getDeliveryServicesResponse(parameters map[string]string, db *sqlx.DB) 
(*tc.DeliveryServicesResponse, []error, tc.ApiErrorType) {
+       dses, errs, errType := getDeliveryServices(parameters, db)
+       if len(errs) > 0 {
+               return nil, errs, errType
        }
 
        resp := tc.DeliveryServicesResponse{
                Response: dses,
        }
-       return &resp, nil
+       return &resp, nil, tc.NoError
 }
 
-func getDeliveryServices(v url.Values, db *sqlx.DB) ([]tc.DeliveryService, 
error) {
+func getDeliveryServices(parameters map[string]string, db *sqlx.DB) 
([]tc.DeliveryService, []error, tc.ApiErrorType) {
        var rows *sqlx.Rows
        var err error
 
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToQueryCols := map[string]string{
-               "xmlId": "xml_id",
+       queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+               "xmlId": dbhelpers.WhereColumnInfo{"xml_id", nil},
        }
 
-       query, queryValues := dbhelpers.BuildQuery(v, selectDSesQuery(), 
queryParamsToQueryCols)
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(parameters, queryParamsToQueryCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
+       }
+       query := selectDSesQuery() + where + orderBy
 
        rows, err = db.NamedQuery(query, queryValues)
        fmt.Printf("rows ---> %v\n", rows)
        fmt.Printf("err ---> %v\n", err)
        if err != nil {
-               return nil, err
+               return nil, []error{err}, tc.SystemError
        }
        defer rows.Close()
 
@@ -103,11 +98,11 @@ func getDeliveryServices(v url.Values, db *sqlx.DB) 
([]tc.DeliveryService, error
        for rows.Next() {
                var s tc.DeliveryService
                if err = rows.StructScan(&s); err != nil {
-                       return nil, fmt.Errorf("getting Delivery Services: %v", 
err)
+                       return nil, []error{fmt.Errorf("getting Delivery 
Services: %v", err)}, tc.SystemError
                }
                dses = append(dses, s)
        }
-       return dses, nil
+       return dses, nil, tc.NoError
 }
 
 func selectDSesQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/divisions.go 
b/traffic_ops/traffic_ops_golang/divisions.go
index 556a22a4ef..10eac0bc99 100644
--- a/traffic_ops/traffic_ops_golang/divisions.go
+++ b/traffic_ops/traffic_ops_golang/divisions.go
@@ -23,9 +23,10 @@ import (
        "encoding/json"
        "fmt"
        "net/http"
-       "net/url"
 
+       "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
+       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
        "github.com/jmoiron/sqlx"
 )
@@ -34,10 +35,15 @@ func divisionsHandler(db *sqlx.DB) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-               q := r.URL.Query()
-               resp, err := getDivisionsResponse(q, db)
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
+               }
+
+               resp, errs, errType := getDivisionsResponse(params, db)
+               if len(errs) > 0 {
+                       tc.HandleErrorsWithType(errs, errType, handleErrs)
                        return
                }
 
@@ -52,34 +58,40 @@ func divisionsHandler(db *sqlx.DB) http.HandlerFunc {
        }
 }
 
-func getDivisionsResponse(q url.Values, db *sqlx.DB) (*tc.DivisionsResponse, 
error) {
-       divisions, err := getDivisions(q, db)
-       if err != nil {
-               return nil, fmt.Errorf("getting divisions response: %v", err)
+func getDivisionsResponse(params map[string]string, db *sqlx.DB) 
(*tc.DivisionsResponse, []error, tc.ApiErrorType) {
+       divisions, errs, errType := getDivisions(params, db)
+       if len(errs) > 0 {
+               return nil, errs, errType
        }
 
        resp := tc.DivisionsResponse{
                Response: divisions,
        }
-       return &resp, nil
+       return &resp, nil, tc.NoError
 }
 
-func getDivisions(v url.Values, db *sqlx.DB) ([]tc.Division, error) {
+func getDivisions(params map[string]string, db *sqlx.DB) ([]tc.Division, 
[]error, tc.ApiErrorType) {
        var rows *sqlx.Rows
        var err error
 
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToSQLCols := map[string]string{
-               "id":   "id",
-               "name": "name",
+       queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{
+               "id":   dbhelpers.WhereColumnInfo{"id", api.IsInt},
+               "name": dbhelpers.WhereColumnInfo{"name", nil},
+       }
+
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(params, queryParamsToSQLCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
        }
 
-       query, queryValues := dbhelpers.BuildQuery(v, selectDivisionsQuery(), 
queryParamsToSQLCols)
+       query := selectDivisionsQuery() + where + orderBy
+       log.Debugln("Query is ", query)
 
        rows, err = db.NamedQuery(query, queryValues)
        if err != nil {
-               return nil, err
+               return nil, []error{err}, tc.SystemError
        }
        defer rows.Close()
 
@@ -87,11 +99,11 @@ func getDivisions(v url.Values, db *sqlx.DB) 
([]tc.Division, error) {
        for rows.Next() {
                var d tc.Division
                if err = rows.StructScan(&d); err != nil {
-                       return nil, fmt.Errorf("getting divisions: %v", err)
+                       return nil, []error{fmt.Errorf("getting divisions: %v", 
err)}, tc.SystemError
                }
                o = append(o, d)
        }
-       return o, nil
+       return o, nil, tc.NoError
 }
 
 func selectDivisionsQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/divisions_test.go 
b/traffic_ops/traffic_ops_golang/divisions_test.go
index 15fcba14ab..636b3fb514 100644
--- a/traffic_ops/traffic_ops_golang/divisions_test.go
+++ b/traffic_ops/traffic_ops_golang/divisions_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-       "net/url"
        "testing"
        "time"
 
@@ -69,12 +68,11 @@ func TestGetDivisions(t *testing.T) {
                )
        }
        mock.ExpectQuery("SELECT").WillReturnRows(rows)
-       v := url.Values{}
-       v.Set("dsId", "1")
+       v := map[string]string{"dsId": "1"}
 
-       servers, err := getDivisions(v, db)
-       if err != nil {
-               t.Errorf("getDivisions expected: nil error, actual: %v", err)
+       servers, errs, errType := getDivisions(v, db)
+       if len(errs) > 0 {
+               t.Errorf("getDivisions expected: no errors, actual: %v with 
error type: %s", errs, errType.String())
        }
 
        if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/hwinfo.go 
b/traffic_ops/traffic_ops_golang/hwinfo.go
index a50b949237..2502dbf30e 100644
--- a/traffic_ops/traffic_ops_golang/hwinfo.go
+++ b/traffic_ops/traffic_ops_golang/hwinfo.go
@@ -23,9 +23,10 @@ import (
        "encoding/json"
        "fmt"
        "net/http"
-       "net/url"
 
+       "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
+       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
        "github.com/jmoiron/sqlx"
 )
@@ -34,10 +35,15 @@ func hwInfoHandler(db *sqlx.DB) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-               q := r.URL.Query()
-               resp, err := getHWInfoResponse(q, db)
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
+               }
+
+               resp, errs, errType := getHWInfoResponse(params, db)
+               if len(errs) > 0 {
+                       tc.HandleErrorsWithType(errs, errType, handleErrs)
                        return
                }
 
@@ -52,38 +58,44 @@ func hwInfoHandler(db *sqlx.DB) http.HandlerFunc {
        }
 }
 
-func getHWInfoResponse(q url.Values, db *sqlx.DB) (*tc.HWInfoResponse, error) {
-       hwInfo, err := getHWInfo(q, db)
-       if err != nil {
-               return nil, fmt.Errorf("getting hwInfo response: %v", err)
+func getHWInfoResponse(params map[string]string, db *sqlx.DB) 
(*tc.HWInfoResponse, []error, tc.ApiErrorType) {
+       hwInfo, errs, errType := getHWInfo(params, db)
+       if len(errs) > 0 {
+               return nil, errs, errType
        }
 
        resp := tc.HWInfoResponse{
                Response: hwInfo,
        }
-       return &resp, nil
+       return &resp, nil, tc.NoError
 }
 
-func getHWInfo(v url.Values, db *sqlx.DB) ([]tc.HWInfo, error) {
+func getHWInfo(params map[string]string, db *sqlx.DB) ([]tc.HWInfo, []error, 
tc.ApiErrorType) {
        var rows *sqlx.Rows
        var err error
 
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToSQLCols := map[string]string{
-               "id":             "h.id",
-               "serverHostName": "s.serverHostName",
-               "serverId":       "s.serverid",
-               "description":    "h.description",
-               "val":            "h.val",
-               "lastUpdated":    "h.last_updated",
+       queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{
+               "id":             dbhelpers.WhereColumnInfo{"h.id", api.IsInt},
+               "serverHostName": dbhelpers.WhereColumnInfo{"s.host_name", nil},
+               "serverId":       dbhelpers.WhereColumnInfo{"s.id", api.IsInt}, 
// TODO: this can be either s.id or h.serverid not sure what makes the most 
sense
+               "description":    dbhelpers.WhereColumnInfo{"h.description", 
nil},
+               "val":            dbhelpers.WhereColumnInfo{"h.val", nil},
+               "lastUpdated":    dbhelpers.WhereColumnInfo{"h.last_updated", 
nil}, //TODO: this doesn't appear to work needs debugging
+       }
+
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(params, queryParamsToSQLCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
        }
 
-       query, queryValues := dbhelpers.BuildQuery(v, selectHWInfoQuery(), 
queryParamsToSQLCols)
+       query := selectHWInfoQuery() + where + orderBy
+       log.Debugln("Query is ", query)
 
        rows, err = db.NamedQuery(query, queryValues)
        if err != nil {
-               return nil, err
+               return nil, []error{err}, tc.SystemError
        }
        defer rows.Close()
 
@@ -91,11 +103,11 @@ func getHWInfo(v url.Values, db *sqlx.DB) ([]tc.HWInfo, 
error) {
        for rows.Next() {
                var s tc.HWInfo
                if err = rows.StructScan(&s); err != nil {
-                       return nil, fmt.Errorf("getting hwInfo: %v", err)
+                       return nil, []error{fmt.Errorf("getting hwInfo: %v", 
err)}, tc.SystemError
                }
                hwInfo = append(hwInfo, s)
        }
-       return hwInfo, nil
+       return hwInfo, nil, tc.NoError
 }
 
 func selectHWInfoQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/hwinfo_test.go 
b/traffic_ops/traffic_ops_golang/hwinfo_test.go
index 507dd8cf92..0a2a4f899c 100644
--- a/traffic_ops/traffic_ops_golang/hwinfo_test.go
+++ b/traffic_ops/traffic_ops_golang/hwinfo_test.go
@@ -22,7 +22,6 @@ package main
 import (
        "encoding/json"
        "fmt"
-       "net/url"
        "testing"
        "time"
 
@@ -82,12 +81,11 @@ func TestGetHWInfo(t *testing.T) {
                )
        }
        mock.ExpectQuery("SELECT").WillReturnRows(rows)
-       v := url.Values{}
-       v.Set("ServerId", "1")
+       v := map[string]string{"ServerId": "1"}
 
-       hwinfos, err := getHWInfo(v, db)
-       if err != nil {
-               t.Errorf("getHWInfo expected: nil error, actual: %v", err)
+       hwinfos, errs, errType := getHWInfo(v, db)
+       if len(errs) > 0 {
+               t.Errorf("getHWInfo expected: no errors, actual: %v with error 
type: %s", errs, errType.String())
        }
 
        if len(hwinfos) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/monitoring.go 
b/traffic_ops/traffic_ops_golang/monitoring.go
index fd3ba8c115..57f1de81b8 100644
--- a/traffic_ops/traffic_ops_golang/monitoring.go
+++ b/traffic_ops/traffic_ops_golang/monitoring.go
@@ -30,6 +30,7 @@ import (
        "github.com/jmoiron/sqlx"
        "github.com/lib/pq"
 
+       "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
 )
@@ -133,18 +134,17 @@ func monitoringHandler(db *sqlx.DB) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-               ctx := r.Context()
-               pathParams, err := api.GetPathParams(ctx)
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
-                       return
                }
 
-               cdnName := pathParams["name"]
+               cdnName := params["name"]
 
-               resp, err := getMonitoringJSON(cdnName, db)
+               resp, err, errType := getMonitoringJSON(cdnName, db)
                if err != nil {
-                       handleErrs(http.StatusInternalServerError, err)
+                       tc.HandleErrorsWithType([]error{err}, errType, 
handleErrs)
                        return
                }
 
@@ -416,30 +416,30 @@ WHERE pr.config_file = '%s'
        return cfg, nil
 }
 
-func getMonitoringJSON(cdnName string, db *sqlx.DB) (*MonitoringResponse, 
error) {
+func getMonitoringJSON(cdnName string, db *sqlx.DB) (*MonitoringResponse, 
error, tc.ApiErrorType) {
        monitors, caches, routers, err := getMonitoringServers(db, cdnName)
        if err != nil {
-               return nil, fmt.Errorf("error getting servers: %v", err)
+               return nil, fmt.Errorf("error getting servers: %v", err), 
tc.SystemError
        }
 
        cachegroups, err := getCachegroups(db, cdnName)
        if err != nil {
-               return nil, fmt.Errorf("error getting cachegroups: %v", err)
+               return nil, fmt.Errorf("error getting cachegroups: %v", err), 
tc.SystemError
        }
 
        profiles, err := getProfiles(db, caches, routers)
        if err != nil {
-               return nil, fmt.Errorf("error getting profiles: %v", err)
+               return nil, fmt.Errorf("error getting profiles: %v", err), 
tc.SystemError
        }
 
        deliveryServices, err := getDeliveryServices(db, routers)
        if err != nil {
-               return nil, fmt.Errorf("error getting deliveryservices: %v", 
err)
+               return nil, fmt.Errorf("error getting deliveryservices: %v", 
err), tc.SystemError
        }
 
        config, err := getConfig(db)
        if err != nil {
-               return nil, fmt.Errorf("error getting config: %v", err)
+               return nil, fmt.Errorf("error getting config: %v", err), 
tc.SystemError
        }
 
        resp := MonitoringResponse{
@@ -452,5 +452,5 @@ func getMonitoringJSON(cdnName string, db *sqlx.DB) 
(*MonitoringResponse, error)
                        Config:           config,
                },
        }
-       return &resp, nil
+       return &resp, nil, tc.NoError
 }
diff --git a/traffic_ops/traffic_ops_golang/monitoring_test.go 
b/traffic_ops/traffic_ops_golang/monitoring_test.go
index d31171bc69..f7dbc364fe 100644
--- a/traffic_ops/traffic_ops_golang/monitoring_test.go
+++ b/traffic_ops/traffic_ops_golang/monitoring_test.go
@@ -615,9 +615,9 @@ func TestGetMonitoringJSON(t *testing.T) {
                resp.Response.Config = config
        }
 
-       sqlResp, err := getMonitoringJSON(cdn, db)
+       sqlResp, err, errType := getMonitoringJSON(cdn, db)
        if err != nil {
-               t.Errorf("getMonitoringJSON expected: nil error, actual: %v", 
err)
+               t.Errorf("getMonitoringJSON expected: nil error, actual: %v 
with error type: %s", err, errType.String())
        }
 
        resp.Response.TrafficServers = sortCaches(resp.Response.TrafficServers)
diff --git a/traffic_ops/traffic_ops_golang/parameters.go 
b/traffic_ops/traffic_ops_golang/parameters.go
index 8025403889..bbba922906 100644
--- a/traffic_ops/traffic_ops_golang/parameters.go
+++ b/traffic_ops/traffic_ops_golang/parameters.go
@@ -23,10 +23,10 @@ import (
        "encoding/json"
        "fmt"
        "net/http"
-       "net/url"
 
        "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
+       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
 
@@ -45,10 +45,15 @@ func parametersHandler(db *sqlx.DB) http.HandlerFunc {
                }
                privLevel := user.PrivLevel
 
-               q := r.URL.Query()
-               resp, err := getParametersResponse(q, db, privLevel)
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
+               }
+
+               resp, errs, errType := getParametersResponse(params, db, 
privLevel)
+               if len(errs) > 0 {
+                       tc.HandleErrorsWithType(errs, errType, handleErrs)
                        return
                }
 
@@ -63,40 +68,44 @@ func parametersHandler(db *sqlx.DB) http.HandlerFunc {
        }
 }
 
-func getParametersResponse(q url.Values, db *sqlx.DB, privLevel int) 
(*tc.ParametersResponse, error) {
-       parameters, err := getParameters(q, db, privLevel)
-       if err != nil {
-               return nil, fmt.Errorf("getting parameters response: %v", err)
+func getParametersResponse(params map[string]string, db *sqlx.DB, privLevel 
int) (*tc.ParametersResponse, []error, tc.ApiErrorType) {
+       parameters, errs, errType := getParameters(params, db, privLevel)
+       if len(errs) > 0 {
+               return nil, errs, errType
        }
 
        resp := tc.ParametersResponse{
                Response: parameters,
        }
-       return &resp, nil
+       return &resp, nil, tc.NoError
 }
 
-func getParameters(v url.Values, db *sqlx.DB, privLevel int) ([]tc.Parameter, 
error) {
+func getParameters(params map[string]string, db *sqlx.DB, privLevel int) 
([]tc.Parameter, []error, tc.ApiErrorType) {
 
        var rows *sqlx.Rows
        var err error
 
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToSQLCols := map[string]string{
-               "config_file":  "p.config_file",
-               "id":           "p.id",
-               "last_updated": "p.last_updated",
-               "name":         "p.name",
-               "secure":       "p.secure",
+       queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{
+               "config_file":  dbhelpers.WhereColumnInfo{"p.config_file", nil},
+               "id":           dbhelpers.WhereColumnInfo{"p.id", api.IsInt},
+               "last_updated": dbhelpers.WhereColumnInfo{"p.last_updated", 
nil},
+               "name":         dbhelpers.WhereColumnInfo{"p.name", nil},
+               "secure":       dbhelpers.WhereColumnInfo{"p.secure", 
api.IsBool},
        }
 
-       query, queryValues := dbhelpers.BuildQuery(v, selectParametersQuery(), 
queryParamsToSQLCols)
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(params, queryParamsToSQLCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
+       }
 
-       query += ParametersGroupBy()
+       query := selectParametersQuery() + where + ParametersGroupBy() + orderBy
        log.Debugln("Query is ", query)
+
        rows, err = db.NamedQuery(query, queryValues)
        if err != nil {
-               return nil, fmt.Errorf("querying: %v", err)
+               return nil, []error{fmt.Errorf("querying: %v", err)}, 
tc.SystemError
        }
        defer rows.Close()
 
@@ -104,7 +113,7 @@ func getParameters(v url.Values, db *sqlx.DB, privLevel 
int) ([]tc.Parameter, er
        for rows.Next() {
                var s tc.Parameter
                if err = rows.StructScan(&s); err != nil {
-                       return nil, fmt.Errorf("getting parameters: %v", err)
+                       return nil, []error{fmt.Errorf("getting parameters: 
%v", err)}, tc.SystemError
                }
                if s.Secure && privLevel < auth.PrivLevelAdmin {
                        // Secure params only visible to admin
@@ -112,7 +121,7 @@ func getParameters(v url.Values, db *sqlx.DB, privLevel 
int) ([]tc.Parameter, er
                }
                parameters = append(parameters, s)
        }
-       return parameters, nil
+       return parameters, nil, tc.NoError
 }
 
 func selectParametersQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/parameters_test.go 
b/traffic_ops/traffic_ops_golang/parameters_test.go
index 3a0616e2aa..8a26b6b048 100644
--- a/traffic_ops/traffic_ops_golang/parameters_test.go
+++ b/traffic_ops/traffic_ops_golang/parameters_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-       "net/url"
        "testing"
        "time"
 
@@ -85,12 +84,11 @@ func TestGetParameters(t *testing.T) {
                )
        }
        mock.ExpectQuery("SELECT").WillReturnRows(rows)
-       v := url.Values{}
-       v.Set("dsId", "1")
+       v := map[string]string{"dsId": "1"}
 
-       parameters, err := getParameters(v, db, auth.PrivLevelAdmin)
-       if err != nil {
-               t.Errorf("getParameters expected: nil error, actual: %v", err)
+       parameters, errs, errType := getParameters(v, db, auth.PrivLevelAdmin)
+       if len(errs) > 0 {
+               t.Errorf("getParameters expected: no errors, actual: %v with 
error type: %s", errs, errType.String())
        }
 
        if len(parameters) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/phys_locations.go 
b/traffic_ops/traffic_ops_golang/phys_locations.go
index 538970d950..b76cafbabd 100644
--- a/traffic_ops/traffic_ops_golang/phys_locations.go
+++ b/traffic_ops/traffic_ops_golang/phys_locations.go
@@ -23,8 +23,8 @@ import (
        "encoding/json"
        "fmt"
        "net/http"
-       "net/url"
 
+       "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
@@ -35,21 +35,15 @@ func physLocationsHandler(db *sqlx.DB) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-               ctx := r.Context()
-               pathParams, err := api.GetPathParams(ctx)
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
-                       return
                }
 
-               // Load the PathParams into the query parameters for pass 
through
-               q := r.URL.Query()
-               for k, v := range pathParams {
-                       q.Set(k, v)
-               }
-               resp, err := getPhysLocationsResponse(q, db)
-               if err != nil {
-                       handleErrs(http.StatusInternalServerError, err)
+               resp, errs, errType := getPhysLocationsResponse(params, db)
+               if len(errs) > 0 {
+                       tc.HandleErrorsWithType(errs, errType, handleErrs)
                        return
                }
 
@@ -64,34 +58,39 @@ func physLocationsHandler(db *sqlx.DB) http.HandlerFunc {
        }
 }
 
-func getPhysLocationsResponse(q url.Values, db *sqlx.DB) 
(*tc.PhysLocationsResponse, error) {
-       physLocations, err := getPhysLocations(q, db)
-       if err != nil {
-               return nil, fmt.Errorf("getting physLocations response: %v", 
err)
+func getPhysLocationsResponse(params map[string]string, db *sqlx.DB) 
(*tc.PhysLocationsResponse, []error, tc.ApiErrorType) {
+       physLocations, errs, errType := getPhysLocations(params, db)
+       if len(errs) > 0 {
+               return nil, errs, errType
        }
-
        resp := tc.PhysLocationsResponse{
                Response: physLocations,
        }
-       return &resp, nil
+       return &resp, nil, tc.NoError
 }
 
-func getPhysLocations(v url.Values, db *sqlx.DB) ([]tc.PhysLocation, error) {
+func getPhysLocations(params map[string]string, db *sqlx.DB) 
([]tc.PhysLocation, []error, tc.ApiErrorType) {
        var rows *sqlx.Rows
        var err error
 
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToQueryCols := map[string]string{
-               "id":     "pl.id",
-               "region": "pl.region",
+       queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+               "id":     dbhelpers.WhereColumnInfo{"pl.id", api.IsInt},
+               "region": dbhelpers.WhereColumnInfo{"pl.region", api.IsInt},
+       }
+
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(params, queryParamsToQueryCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
        }
 
-       query, queryValues := dbhelpers.BuildQuery(v, 
selectPhysLocationsQuery(), queryParamsToQueryCols)
+       query := selectPhysLocationsQuery() + where + orderBy
+       log.Debugln("Query is ", query)
 
        rows, err = db.NamedQuery(query, queryValues)
        if err != nil {
-               return nil, err
+               return nil, []error{err}, tc.SystemError
        }
        defer rows.Close()
 
@@ -99,11 +98,11 @@ func getPhysLocations(v url.Values, db *sqlx.DB) 
([]tc.PhysLocation, error) {
        for rows.Next() {
                var s tc.PhysLocation
                if err = rows.StructScan(&s); err != nil {
-                       return nil, fmt.Errorf("getting physLocations: %v", err)
+                       return nil, []error{fmt.Errorf("getting physLocations: 
%v", err)}, tc.SystemError
                }
                physLocations = append(physLocations, s)
        }
-       return physLocations, nil
+       return physLocations, nil, tc.NoError
 }
 
 func selectPhysLocationsQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/phys_locations_test.go 
b/traffic_ops/traffic_ops_golang/phys_locations_test.go
index 65e02f1b3e..b47c69c9bb 100644
--- a/traffic_ops/traffic_ops_golang/phys_locations_test.go
+++ b/traffic_ops/traffic_ops_golang/phys_locations_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-       "net/url"
        "testing"
        "time"
 
@@ -90,12 +89,11 @@ func TestGetPhysLocations(t *testing.T) {
                )
        }
        mock.ExpectQuery("SELECT").WillReturnRows(rows)
-       v := url.Values{}
-       v.Set("dsId", "1")
+       v := map[string]string{"dsId": "1"}
 
-       servers, err := getPhysLocations(v, db)
-       if err != nil {
-               t.Errorf("getPhysLocations expected: nil error, actual: %v", 
err)
+       servers, errs, errType := getPhysLocations(v, db)
+       if len(errs) > 0 {
+               t.Errorf("getPhysLocations expected: no errors, actual: %v with 
error type: %s", err, errType.String())
        }
 
        if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/regions.go 
b/traffic_ops/traffic_ops_golang/regions.go
index 7f8f85dbda..66e06ef97e 100644
--- a/traffic_ops/traffic_ops_golang/regions.go
+++ b/traffic_ops/traffic_ops_golang/regions.go
@@ -23,8 +23,8 @@ import (
        "encoding/json"
        "fmt"
        "net/http"
-       "net/url"
 
+       "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
@@ -35,21 +35,15 @@ func regionsHandler(db *sqlx.DB) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-               ctx := r.Context()
-               pathParams, err := api.GetPathParams(ctx)
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
-                       return
                }
 
-               // Load the PathParams into the query parameters for pass 
through
-               q := r.URL.Query()
-               for k, v := range pathParams {
-                       q.Set(k, v)
-               }
-               resp, err := getRegionsResponse(q, db)
-               if err != nil {
-                       handleErrs(http.StatusInternalServerError, err)
+               resp, errs, errType := getRegionsResponse(params, db)
+               if len(errs) > 0 {
+                       tc.HandleErrorsWithType(errs, errType, handleErrs)
                        return
                }
 
@@ -64,35 +58,41 @@ func regionsHandler(db *sqlx.DB) http.HandlerFunc {
        }
 }
 
-func getRegionsResponse(q url.Values, db *sqlx.DB) (*tc.RegionsResponse, 
error) {
-       regions, err := getRegions(q, db)
-       if err != nil {
-               return nil, fmt.Errorf("getting regions response: %v", err)
+func getRegionsResponse(params map[string]string, db *sqlx.DB) 
(*tc.RegionsResponse, []error, tc.ApiErrorType) {
+       regions, errs, errType := getRegions(params, db)
+       if len(errs) > 0 {
+               return nil, errs, errType
        }
 
        resp := tc.RegionsResponse{
                Response: regions,
        }
-       return &resp, nil
+       return &resp, nil, tc.NoError
 }
 
-func getRegions(v url.Values, db *sqlx.DB) ([]tc.Region, error) {
+func getRegions(params map[string]string, db *sqlx.DB) ([]tc.Region, []error, 
tc.ApiErrorType) {
        var rows *sqlx.Rows
        var err error
 
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToQueryCols := map[string]string{
-               "division": "d.id",
-               "id":       "r.id",
-               "name":     "r.name",
+       queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+               "division": dbhelpers.WhereColumnInfo{"d.id", api.IsInt},
+               "id":       dbhelpers.WhereColumnInfo{"r.id", api.IsInt},
+               "name":     dbhelpers.WhereColumnInfo{"r.name", nil},
+       }
+
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(params, queryParamsToQueryCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
        }
 
-       query, queryValues := dbhelpers.BuildQuery(v, selectRegionsQuery(), 
queryParamsToQueryCols)
+       query := selectRegionsQuery() + where + orderBy
+       log.Debugln("Query is ", query)
 
        rows, err = db.NamedQuery(query, queryValues)
        if err != nil {
-               return nil, err
+               return nil, []error{err}, tc.SystemError
        }
        defer rows.Close()
 
@@ -100,11 +100,11 @@ func getRegions(v url.Values, db *sqlx.DB) ([]tc.Region, 
error) {
        for rows.Next() {
                var s tc.Region
                if err = rows.StructScan(&s); err != nil {
-                       return nil, fmt.Errorf("getting regions: %v", err)
+                       return nil, []error{fmt.Errorf("getting regions: %v", 
err)}, tc.SystemError
                }
                regions = append(regions, s)
        }
-       return regions, nil
+       return regions, nil, tc.NoError
 }
 
 func selectRegionsQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/regions_test.go 
b/traffic_ops/traffic_ops_golang/regions_test.go
index 010ba1998c..1b18d75c0b 100644
--- a/traffic_ops/traffic_ops_golang/regions_test.go
+++ b/traffic_ops/traffic_ops_golang/regions_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-       "net/url"
        "testing"
        "time"
 
@@ -72,12 +71,11 @@ func TestGetRegions(t *testing.T) {
                )
        }
        mock.ExpectQuery("SELECT").WillReturnRows(rows)
-       v := url.Values{}
-       v.Set("dsId", "1")
+       v := map[string]string{"dsId": "1"}
 
-       servers, err := getRegions(v, db)
-       if err != nil {
-               t.Errorf("getRegions expected: nil error, actual: %v", err)
+       servers, errs, errType := getRegions(v, db)
+       if len(errs) > 0 {
+               t.Errorf("getRegions expected: no errors, actual: %v with error 
type: %s", errs, errType.String())
        }
 
        if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/routing.go 
b/traffic_ops/traffic_ops_golang/routing.go
index af6f25d4be..070ac750b6 100644
--- a/traffic_ops/traffic_ops_golang/routing.go
+++ b/traffic_ops/traffic_ops_golang/routing.go
@@ -165,7 +165,7 @@ func Handler(routes map[string][]CompiledRoute, catchall 
http.Handler, w http.Re
 
                ctx := r.Context()
 
-               params := api.PathParams{}
+               params := map[string]string{}
                for i, v := range compiledRoute.Params {
                        params[v] = match[i+1]
                }
diff --git a/traffic_ops/traffic_ops_golang/servers.go 
b/traffic_ops/traffic_ops_golang/servers.go
index 1d2f34e43a..64e3526269 100644
--- a/traffic_ops/traffic_ops_golang/servers.go
+++ b/traffic_ops/traffic_ops_golang/servers.go
@@ -24,7 +24,6 @@ import (
        "errors"
        "fmt"
        "net/http"
-       "net/url"
        "strconv"
 
        "github.com/apache/incubator-trafficcontrol/lib/go-log"
@@ -49,28 +48,21 @@ func serversHandler(db *sqlx.DB) http.HandlerFunc {
                }
                privLevel := user.PrivLevel
 
-               pathParams, err := api.GetPathParams(ctx)
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
-                       return
                }
 
-               q := r.URL.Query()
-               // TODO: move this checking to a common area so all endpoints 
can use it
-               for k, v := range pathParams {
-                       if k == `id` {
-                               if _, err := strconv.Atoi(v); err != nil {
-                                       log.Errorf("Expected {id} to be an 
integer: %s", v)
-                                       handleErrs(http.StatusNotFound, 
errors.New("Resource not found")) //matches perl response
+               resp, errs, errType := getServersResponse(params, db, privLevel)
+               if len(errs) > 0 {
+                       for _, err := range errs {
+                               if err.Error() == `id cannot parse to integer` {
+                                       handleErrs(http.StatusNotFound, 
errors.New("Resource not found.")) //matches perl response
                                        return
                                }
                        }
-                       q.Set(k, v)
-               }
-               resp, err := getServersResponse(q, db, privLevel)
-               if err != nil {
-                       log.Errorln(err)
-                       handleErrs(http.StatusInternalServerError, err)
+                       tc.HandleErrorsWithType(errs, errType, handleErrs)
                        return
                }
 
@@ -86,41 +78,47 @@ func serversHandler(db *sqlx.DB) http.HandlerFunc {
        }
 }
 
-func getServersResponse(v url.Values, db *sqlx.DB, privLevel int) 
(*tc.ServersResponse, error) {
-       servers, err := getServers(v, db, privLevel)
-       if err != nil {
-               return nil, fmt.Errorf("getting servers response: %v", err)
+func getServersResponse(params map[string]string, db *sqlx.DB, privLevel int) 
(*tc.ServersResponse, []error, tc.ApiErrorType) {
+       servers, errs, errType := getServers(params, db, privLevel)
+       if len(errs) > 0 {
+               return nil, errs, errType
        }
 
        resp := tc.ServersResponse{
                Response: servers,
        }
-       return &resp, nil
+       return &resp, nil, tc.NoError
 }
 
-func getServers(v url.Values, db *sqlx.DB, privLevel int) ([]tc.Server, error) 
{
+func getServers(params map[string]string, db *sqlx.DB, privLevel int) 
([]tc.Server, []error, tc.ApiErrorType) {
 
        var rows *sqlx.Rows
        var err error
 
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToSQLCols := map[string]string{
-               "cachegroup":   "s.cachegroup",
-               "cdn":          "s.cdn_id",
-               "id":           "s.id",
-               "hostName":     "s.host_name",
-               "physLocation": "s.phys_location",
-               "profileId":    "s.profile",
-               "status":       "st.name",
-               "type":         "t.name",
+       queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{
+               "cachegroup":   dbhelpers.WhereColumnInfo{"s.cachegroup", 
api.IsInt},
+               "cdn":          dbhelpers.WhereColumnInfo{"s.cdn_id", 
api.IsInt},
+               "id":           dbhelpers.WhereColumnInfo{"s.id", api.IsInt},
+               "hostName":     dbhelpers.WhereColumnInfo{"s.host_name", nil},
+               "physLocation": dbhelpers.WhereColumnInfo{"s.phys_location", 
api.IsInt},
+               "profileId":    dbhelpers.WhereColumnInfo{"s.profile", 
api.IsInt},
+               "status":       dbhelpers.WhereColumnInfo{"st.name", nil},
+               "type":         dbhelpers.WhereColumnInfo{"t.name", nil},
+       }
+
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(params, queryParamsToSQLCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
        }
 
-       query, queryValues := dbhelpers.BuildQuery(v, selectServersQuery(), 
queryParamsToSQLCols)
+       query := selectServersQuery() + where + orderBy
+       log.Debugln("Query is ", query)
 
        rows, err = db.NamedQuery(query, queryValues)
        if err != nil {
-               return nil, fmt.Errorf("querying: %v", err)
+               return nil, []error{fmt.Errorf("querying: %v", err)}, 
tc.SystemError
        }
        defer rows.Close()
 
@@ -131,7 +129,7 @@ func getServers(v url.Values, db *sqlx.DB, privLevel int) 
([]tc.Server, error) {
        for rows.Next() {
                var s tc.Server
                if err = rows.StructScan(&s); err != nil {
-                       return nil, fmt.Errorf("getting servers: %v", err)
+                       return nil, []error{fmt.Errorf("getting servers: %v", 
err)}, tc.SystemError
                }
                if privLevel < auth.PrivLevelAdmin {
                        s.ILOPassword = HiddenField
@@ -139,7 +137,7 @@ func getServers(v url.Values, db *sqlx.DB, privLevel int) 
([]tc.Server, error) {
                }
                servers = append(servers, s)
        }
-       return servers, nil
+       return servers, nil, tc.NoError
 }
 
 func selectServersQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/servers_assignment.go 
b/traffic_ops/traffic_ops_golang/servers_assignment.go
index 872e8bebd1..b04883cd68 100644
--- a/traffic_ops/traffic_ops_golang/servers_assignment.go
+++ b/traffic_ops/traffic_ops_golang/servers_assignment.go
@@ -40,12 +40,10 @@ func assignDeliveryServicesToServerHandler(db *sqlx.DB) 
http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-               // p PathParams, username string, privLevel int
-               ctx := r.Context()
-               pathParams, err := api.GetPathParams(ctx)
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
-                       return
                }
 
                var dsList []int
@@ -56,16 +54,14 @@ func assignDeliveryServicesToServerHandler(db *sqlx.DB) 
http.HandlerFunc {
                        return
                }
 
-               q := r.URL.Query()
-
-               replaceQueryParameter := q["replace"][0]
+               replaceQueryParameter := params["replace"]
                replace, err := strconv.ParseBool(replaceQueryParameter) 
//accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. for replace 
url parameter documentation
                if err != nil {
                        handleErrs(http.StatusBadRequest, err)
                        return
                }
 
-               serverPathParameter := pathParams["id"]
+               serverPathParameter := params["id"]
                server, err := strconv.Atoi(serverPathParameter)
                if err != nil {
                        handleErrs(http.StatusBadRequest, err)
diff --git a/traffic_ops/traffic_ops_golang/servers_test.go 
b/traffic_ops/traffic_ops_golang/servers_test.go
index 0dc1228900..f52d88052d 100644
--- a/traffic_ops/traffic_ops_golang/servers_test.go
+++ b/traffic_ops/traffic_ops_golang/servers_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-       "net/url"
        "testing"
        "time"
 
@@ -159,13 +158,12 @@ func TestGetServersByCachegroup(t *testing.T) {
                )
        }
        mock.ExpectQuery("SELECT").WillReturnRows(rows)
-       v := url.Values{}
-       v.Set("cachegroup", "cachegroup2")
+       v := map[string]string{"cachegroup": "2"}
 
-       servers, err := getServers(v, db, auth.PrivLevelAdmin)
+       servers, errs, errType := getServers(v, db, auth.PrivLevelAdmin)
        log.Debugln("%v-->", servers)
-       if err != nil {
-               t.Errorf("getServers expected: nil error, actual: %v", err)
+       if len(errs) > 0 {
+               t.Errorf("getServers expected: no errors, actual: %v with error 
type: %s", errs, errType.String())
        }
 
        if len(servers) != 3 {
diff --git a/traffic_ops/traffic_ops_golang/servers_update_status.go 
b/traffic_ops/traffic_ops_golang/servers_update_status.go
index 5aa1e726d3..b0282bdd50 100644
--- a/traffic_ops/traffic_ops_golang/servers_update_status.go
+++ b/traffic_ops/traffic_ops_golang/servers_update_status.go
@@ -35,14 +35,12 @@ func getServerUpdateStatusHandler(db *sqlx.DB) 
http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-               // p PathParams, username string, privLevel int
-               ctx := r.Context()
-               pathParams, err := api.GetPathParams(ctx)
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
-                       return
                }
-               hostName := pathParams["host_name"]
+               hostName := params["host_name"]
 
                serverUpdateStatus, err := getServerUpdateStatus(hostName, db)
                if err != nil {
diff --git a/traffic_ops/traffic_ops_golang/statuses.go 
b/traffic_ops/traffic_ops_golang/statuses.go
index f9b5954658..03d38ff13e 100644
--- a/traffic_ops/traffic_ops_golang/statuses.go
+++ b/traffic_ops/traffic_ops_golang/statuses.go
@@ -23,14 +23,11 @@ import (
        "encoding/json"
        "fmt"
        "net/http"
-       "net/url"
-       "strconv"
 
        "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
-       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
-
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
+       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
        "github.com/jmoiron/sqlx"
 )
 
@@ -38,29 +35,15 @@ func statusesHandler(db *sqlx.DB) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-               pathParams, err := api.GetPathParams(r.Context())
+               params, err := api.GetCombinedParams(r)
                if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
                        handleErrs(http.StatusInternalServerError, err)
-                       return
-               }
-
-               q := r.URL.Query()
-
-               for k, v := range pathParams {
-                       if k == `id` {
-                               if _, err := strconv.Atoi(v); err != nil {
-                                       log.Errorf("Expected {id} to be an 
integer: %s", v)
-                                       handleErrs(http.StatusBadRequest, err)
-                                       return
-                               }
-                       }
-                       q.Set(k, v)
                }
 
-               resp, err := getStatusesResponse(q, db)
-
-               if err != nil {
-                       handleErrs(http.StatusInternalServerError, err)
+               resp, errs, errType := getStatusesResponse(params, db)
+               if len(errs) > 0 {
+                       tc.HandleErrorsWithType(errs, errType, handleErrs)
                        return
                }
 
@@ -75,35 +58,41 @@ func statusesHandler(db *sqlx.DB) http.HandlerFunc {
        }
 }
 
-func getStatusesResponse(q url.Values, db *sqlx.DB) (*tc.StatusesResponse, 
error) {
-       cdns, err := getStatuses(q, db)
-       if err != nil {
-               return nil, fmt.Errorf("getting cdns response: %v", err)
+func getStatusesResponse(params map[string]string, db *sqlx.DB) 
(*tc.StatusesResponse, []error, tc.ApiErrorType) {
+       cdns, errs, errType := getStatuses(params, db)
+       if len(errs) > 0 {
+               return nil, errs, errType
        }
 
        resp := tc.StatusesResponse{
                Response: cdns,
        }
-       return &resp, nil
+       return &resp, nil, tc.NoError
 }
 
-func getStatuses(v url.Values, db *sqlx.DB) ([]tc.Status, error) {
+func getStatuses(params map[string]string, db *sqlx.DB) ([]tc.Status, []error, 
tc.ApiErrorType) {
        var rows *sqlx.Rows
        var err error
 
        // Query Parameters to Database Query column mappings
        // see the fields mapped in the SQL query
-       queryParamsToSQLCols := map[string]string{
-               "id":          "id",
-               "name":        "name",
-               "description": "description",
+       queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{
+               "id":          dbhelpers.WhereColumnInfo{"id", api.IsInt},
+               "name":        dbhelpers.WhereColumnInfo{"name", nil},
+               "description": dbhelpers.WhereColumnInfo{"description", nil},
+       }
+
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(params, queryParamsToSQLCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
        }
 
-       query, queryValues := dbhelpers.BuildQuery(v, selectStatusesQuery(), 
queryParamsToSQLCols)
+       query := selectStatusesQuery() + where + orderBy
+       log.Debugln("Query is ", query)
 
        rows, err = db.NamedQuery(query, queryValues)
        if err != nil {
-               return nil, err
+               return nil, []error{err}, tc.SystemError
        }
        defer rows.Close()
 
@@ -111,11 +100,11 @@ func getStatuses(v url.Values, db *sqlx.DB) ([]tc.Status, 
error) {
        for rows.Next() {
                var s tc.Status
                if err = rows.StructScan(&s); err != nil {
-                       return nil, fmt.Errorf("getting statuses: %v", err)
+                       return nil, []error{fmt.Errorf("getting statuses: %v", 
err)}, tc.SystemError
                }
                statuses = append(statuses, s)
        }
-       return statuses, nil
+       return statuses, nil, tc.NoError
 }
 
 func selectStatusesQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/statuses_test.go 
b/traffic_ops/traffic_ops_golang/statuses_test.go
index ed92c5b9bd..6be62e6036 100644
--- a/traffic_ops/traffic_ops_golang/statuses_test.go
+++ b/traffic_ops/traffic_ops_golang/statuses_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-       "net/url"
        "testing"
        "time"
 
@@ -74,12 +73,11 @@ func TestGetStatus(t *testing.T) {
                )
        }
        mock.ExpectQuery("SELECT").WillReturnRows(rows)
-       v := url.Values{}
-       v.Set("dsId", "1")
+       v := map[string]string{"dsId": "1"}
 
-       servers, err := getStatuses(v, db)
-       if err != nil {
-               t.Errorf("getStatus expected: nil error, actual: %v", err)
+       servers, errs, errType := getStatuses(v, db)
+       if len(errs) > 0 {
+               t.Errorf("getStatus expected: no errors, actual: %v with error 
type: %s", errs, errType.String())
        }
 
        if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/tenant/tenancy.go 
b/traffic_ops/traffic_ops_golang/tenant/tenancy.go
index 13a8899280..aea85394e5 100644
--- a/traffic_ops/traffic_ops_golang/tenant/tenancy.go
+++ b/traffic_ops/traffic_ops_golang/tenant/tenancy.go
@@ -22,6 +22,7 @@ package tenant
 import (
        "database/sql"
        "fmt"
+
        "github.com/apache/incubator-trafficcontrol/lib/go-log"
        "github.com/apache/incubator-trafficcontrol/lib/go-tc"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
@@ -47,7 +48,7 @@ func GetDeliveryServiceTenantInfo(xmlId string, db *sqlx.DB) 
(*DeliveryServiceTe
        ds := DeliveryServiceTenantInfo{}
        query := "SELECT xml_id,tenant_id FROM deliveryservice where xml_id = 
$1"
 
-       err := db.Get(&ds,query,xmlId)
+       err := db.Get(&ds, query, xmlId)
        switch {
        case err == sql.ErrNoRows:
                ds = DeliveryServiceTenantInfo{}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to