You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@trafficcontrol.apache.org by GitBox <gi...@apache.org> on 2018/02/08 15:52:15 UTC

[GitHub] dangogh closed pull request #1860: normalize url query parameters handling and where and orderby clause construction

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:
users@infra.apache.org


With regards,
Apache Git Services