diff --git a/service/apis/entity_service.go b/service/apis/entity_service.go index 01d3434..8c5ba08 100644 --- a/service/apis/entity_service.go +++ b/service/apis/entity_service.go @@ -194,6 +194,7 @@ func (s EntityService) SyncEntities(meta string, data []map[string]interface{}) } if !found { s.dbclient.DeleteEntity(uid) + log.Debugf("entity %s deleted by sync", rid) } } } diff --git a/service/apis/qsl_service.go b/service/apis/qsl_service.go index 74c2cef..55cd316 100644 --- a/service/apis/qsl_service.go +++ b/service/apis/qsl_service.go @@ -17,10 +17,10 @@ import ( ) // regex to get objtype[filters]{fields} -var blockRegex = `([a-zA-Z0-9]+)\[?(?:(\@[\(\)\"\,\@\$\=\>\<\~\!a-zA-Z0-9\-\.\|\&\:_\^\*]*|\**|\$\$[a-zA-Z0-9\,\=]+))\]?\{([\*|[\,\@\"\=a-zA-Z0-9\-]*)` +var blockRegex = `([a-zA-Z0-9]+)\[?(?:(\@[\(\)\"\,\@\$\=\>\<\~\!a-zA-Z0-9\/\-\.\|\&\:_\^\*]*|\**|\$\$[a-zA-Z0-9\,\=]+))\]?\{([\*|[\,\@\"\=a-zA-Z0-9\-]*)` // regex to get KeyOperatorValue from something like numreplicas>=2 -var filterRegex = `\@([a-zA-Z0-9\(\)\.\$]*)([\!\<\>\=\~]*)(\"?[a-zA-Z0-9\-\.\|\&\:_\$\^]*\"?)` +var filterRegex = `\@([a-zA-Z0-9-_\(\)\.\$]*)([\!\<\>\=\~]*)(\"?[a-zA-Z0-9\-\\\/\.\|\&\:_\$\^]*\"?)` // QSLService service for QSL type QSLService struct { @@ -438,7 +438,7 @@ func parseQuery(qry string) (string, string, string, error) { objType := strings.ToLower(matches[1]) filters := matches[2] fields := strings.ToLower(matches[3]) - return objType, filters, fields, nil + return objType, strings.Replace(filters, "/", "\\/", -1), fields, nil } func (qa *QSLService) getCntFilter(query, objType string) (string, error) { diff --git a/service/resources/server_resource.go b/service/resources/server_resource.go index 4bb9507..a119b22 100644 --- a/service/resources/server_resource.go +++ b/service/resources/server_resource.go @@ -34,9 +34,7 @@ type ServerResource struct { // EntityGetHandler REST API for get Entity func (s ServerResource) EntityGetHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -44,19 +42,18 @@ func (s ServerResource) EntityGetHandler(w http.ResponseWriter, r *http.Request) w.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) uid := vars[util.UID] - start := time.Now() code := http.StatusOK defer func() { metrics.DgraphGetEntityLatencyHistogram.WithLabelValues(fmt.Sprintf("%d", code)).Observe(time.Since(start).Seconds()) }() - obj, err := s.EntitySvc.GetEntity(uid) if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() code = http.StatusInternalServerError - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } // object not found @@ -64,21 +61,19 @@ func (s ServerResource) EntityGetHandler(w http.ResponseWriter, r *http.Request) metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() code = http.StatusNotFound - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"entity with id %s not found\"}", http.StatusNotFound, uid))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"entity with id %s not found\"}", code, uid))) return } - obj["status"] = http.StatusOK + obj["status"] = code ret, _ := json.Marshal(obj) w.Write(ret) - metrics.KatlasNumReq2xx.Inc() } // MetaGetHandler REST API for get metadata func (s ServerResource) MetaGetHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -90,6 +85,7 @@ func (s ServerResource) MetaGetHandler(w http.ResponseWriter, r *http.Request) { if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -104,14 +100,13 @@ func (s ServerResource) MetaGetHandler(w http.ResponseWriter, r *http.Request) { } metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() + w.WriteHeader(http.StatusNotFound) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"metadata %s not found\"}", http.StatusNotFound, name))) } // MetaDeleteHandler REST API for delete metadata func (s ServerResource) MetaDeleteHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) @@ -120,6 +115,7 @@ func (s ServerResource) MetaDeleteHandler(w http.ResponseWriter, r *http.Request if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() + w.WriteHeader(http.StatusConflict) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusConflict, trim(err.Error())))) return } @@ -134,15 +130,12 @@ func (s ServerResource) MetaDeleteHandler(w http.ResponseWriter, r *http.Request } ret, _ := json.Marshal(msg) w.Write(ret) - metrics.KatlasNumReq2xx.Inc() } // EntityDeleteHandler REST API for delete Entity func (s ServerResource) EntityDeleteHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -163,11 +156,12 @@ func (s ServerResource) EntityDeleteHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() code = http.StatusInternalServerError - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "resourceid": rid, @@ -177,15 +171,12 @@ func (s ServerResource) EntityDeleteHandler(w http.ResponseWriter, r *http.Reque } ret, _ := json.Marshal(msg) w.Write(ret) - metrics.KatlasNumReq2xx.Inc() } // EntityCreateHandler REST API for create Entity func (s ServerResource) EntityCreateHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -194,22 +185,26 @@ func (s ServerResource) EntityCreateHandler(w http.ResponseWriter, r *http.Reque vars := mux.Vars(r) meta := vars[util.Metadata] clusterName := r.Header.Get(util.ClusterName) - + code := http.StatusOK body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) + return } payload, err := buildEntityData(clusterName, meta, body, false) if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } - start := time.Now() - code := http.StatusOK defer func() { metrics.DgraphCreateEntityLatencyHistogram.WithLabelValues(fmt.Sprintf("%d", code)).Observe(time.Since(start).Seconds()) }() @@ -218,13 +213,14 @@ func (s ServerResource) EntityCreateHandler(w http.ResponseWriter, r *http.Reque if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() - code = http.StatusInternalServerError log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + code = http.StatusInternalServerError + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "uid": uid, @@ -234,15 +230,12 @@ func (s ServerResource) EntityCreateHandler(w http.ResponseWriter, r *http.Reque } ret, _ := json.Marshal(msg) w.Write(ret) - metrics.KatlasNumReq2xx.Inc() } // EntityUpdateHandler REST API for update Entity func (s ServerResource) EntityUpdateHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -252,10 +245,14 @@ func (s ServerResource) EntityUpdateHandler(w http.ResponseWriter, r *http.Reque vars := mux.Vars(r) meta := vars[util.Metadata] uuid := vars[util.UID] - + code := http.StatusOK body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) + return } payload := make(map[string]interface{}, 0) err = json.Unmarshal(body, &payload) @@ -263,12 +260,12 @@ func (s ServerResource) EntityUpdateHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } - start := time.Now() - code := http.StatusOK defer func() { metrics.DgraphUpdateEntityLatencyHistogram.WithLabelValues(fmt.Sprintf("%d", code)).Observe(time.Since(start).Seconds()) }() @@ -277,13 +274,14 @@ func (s ServerResource) EntityUpdateHandler(w http.ResponseWriter, r *http.Reque if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() - code = http.StatusInternalServerError log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + code = http.StatusInternalServerError + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "uid": uuid, @@ -299,9 +297,6 @@ func (s ServerResource) EntityUpdateHandler(w http.ResponseWriter, r *http.Reque // EntitySyncHandler REST API to sync entities func (s ServerResource) EntitySyncHandler(w http.ResponseWriter, r *http.Request) { - - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -310,37 +305,43 @@ func (s ServerResource) EntitySyncHandler(w http.ResponseWriter, r *http.Request vars := mux.Vars(r) meta := vars[util.Metadata] clusterName := r.Header.Get(util.ClusterName) - body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + return } payload, err := buildEntityData(clusterName, meta, body, true) if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } - err = s.EntitySvc.SyncEntities(meta, payload.([]map[string]interface{})) - if err != nil { - metrics.KatlasNumReqErr.Inc() - metrics.KatlasNumReqErr5xx.Inc() - log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) - return - } - w.Write([]byte(fmt.Sprintf("{\"synced\": \"done\", \"type\": \"%s\"}", meta))) - - metrics.KatlasNumReq2xx.Inc() + metrics.KatlasNumReqCount.Inc() + // return status code 202 directly + w.WriteHeader(http.StatusAccepted) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"message\": \"%s sync request accepted\"}", http.StatusAccepted, meta))) + // process by goroutine + go func() { + err = s.EntitySvc.SyncEntities(meta, payload.([]map[string]interface{})) + if err != nil { + metrics.KatlasNumReqErr.Inc() + metrics.KatlasNumReqErr5xx.Inc() + log.Error(err) + return + } + log.Debugf("%s sync completed, total %d synced", meta, len(payload.([]map[string]interface{}))) + metrics.KatlasNumReq2xx.Inc() + }() } // QueryHandler REST API for get Query Response func (s ServerResource) QueryHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -356,13 +357,14 @@ func (s ServerResource) QueryHandler(w http.ResponseWriter, r *http.Request) { obj, err := s.QuerySvc.GetQueryResult(queryMap) if err != nil { - code = http.StatusInternalServerError metrics.KatlasNumReqErr5xx.Inc() metrics.KatlasNumReqErr.Inc() - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + code = http.StatusInternalServerError + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } - obj["status"] = http.StatusOK + obj["status"] = code ret, _ := json.Marshal(obj) w.Write(ret) @@ -371,9 +373,7 @@ func (s ServerResource) QueryHandler(w http.ResponseWriter, r *http.Request) { // MetaCreateHandler REST API for create Metadata func (s ServerResource) MetaCreateHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") body, err := ioutil.ReadAll(r.Body) @@ -386,6 +386,7 @@ func (s ServerResource) MetaCreateHandler(w http.ResponseWriter, r *http.Request metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } @@ -398,6 +399,7 @@ func (s ServerResource) MetaCreateHandler(w http.ResponseWriter, r *http.Request metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() log.Error(err) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -418,6 +420,7 @@ func (s ServerResource) MetaCreateHandler(w http.ResponseWriter, r *http.Request metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() log.Error(err) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -438,9 +441,7 @@ func (s ServerResource) MetaCreateHandler(w http.ResponseWriter, r *http.Request // MetaUpdateHandler REST API for update Metadata func (s ServerResource) MetaUpdateHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) @@ -448,6 +449,9 @@ func (s ServerResource) MetaUpdateHandler(w http.ResponseWriter, r *http.Request body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + return } var payload interface{} err = json.Unmarshal(body, &payload) @@ -455,6 +459,7 @@ func (s ServerResource) MetaUpdateHandler(w http.ResponseWriter, r *http.Request metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } @@ -463,6 +468,7 @@ func (s ServerResource) MetaUpdateHandler(w http.ResponseWriter, r *http.Request metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() log.Error(err) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -484,15 +490,16 @@ func (s ServerResource) MetaUpdateHandler(w http.ResponseWriter, r *http.Request // SchemaUpsertHandler REST API for create Schema func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - defer s.MetaSvc.RemoveSchemaCache(db.LruCache) w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + return } var payload interface{} err = json.Unmarshal(body, &payload) @@ -500,6 +507,7 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } @@ -511,6 +519,7 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } @@ -521,6 +530,7 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque log.Error(err) metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -538,6 +548,7 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } @@ -546,6 +557,7 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() log.Error(err) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -561,20 +573,18 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque // SchemaDropHandler remove db schema func (s ServerResource) SchemaDropHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - defer s.MetaSvc.RemoveSchemaCache(db.LruCache) w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) predicate := vars[util.Name] - err := s.MetaSvc.DropSchema(predicate) if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() log.Error(err) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } diff --git a/service/resources/server_resource_v1.1.go b/service/resources/server_resource_v1.1.go index 6124da6..b5a0dc9 100644 --- a/service/resources/server_resource_v1.1.go +++ b/service/resources/server_resource_v1.1.go @@ -14,9 +14,7 @@ import ( // EntityGetHandlerV1_1 REST API for get Entity func (s ServerResource) EntityGetHandlerV1_1(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -36,7 +34,8 @@ func (s ServerResource) EntityGetHandlerV1_1(w http.ResponseWriter, r *http.Requ metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() code = http.StatusInternalServerError - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } // object not found @@ -44,10 +43,11 @@ func (s ServerResource) EntityGetHandlerV1_1(w http.ResponseWriter, r *http.Requ metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() code = http.StatusNotFound - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"entity with id %s not found\"}", http.StatusNotFound, uid))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"entity with id %s not found\"}", code, uid))) return } - obj["status"] = http.StatusOK + obj["status"] = code ret, _ := json.Marshal(obj) w.Write(ret) @@ -88,11 +88,12 @@ func (s ServerResource) EntityDeleteHandlerV1_1(w http.ResponseWriter, r *http.R metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() code = http.StatusInternalServerError - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "uid": uid, @@ -117,26 +118,34 @@ func (s ServerResource) EntityCreateHandlerV1_1(w http.ResponseWriter, r *http.R w.Header().Set("Content-Type", "application/json") clusterName := r.Header.Get(util.ClusterName) metas, ok := r.URL.Query()[util.ObjType] + code := http.StatusOK if !ok || len(metas[0]) < 1 { - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"metadata not found from parameters\"}", http.StatusBadRequest))) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"metadata not found from parameters\"}", code))) return } meta := metas[0] body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) + return } payload, err := buildEntityData(clusterName, meta, body, false) if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } start := time.Now() - code := http.StatusOK defer func() { metrics.DgraphCreateEntityLatencyHistogram.WithLabelValues(fmt.Sprintf("%d", code)).Observe(time.Since(start).Seconds()) }() @@ -145,13 +154,14 @@ func (s ServerResource) EntityCreateHandlerV1_1(w http.ResponseWriter, r *http.R if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() - code = http.StatusInternalServerError log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + code = http.StatusInternalServerError + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "uid": uid, @@ -178,10 +188,14 @@ func (s ServerResource) EntityUpdateHandlerV1_1(w http.ResponseWriter, r *http.R vars := mux.Vars(r) uuid := vars[util.UID] - + code := http.StatusOK body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"metadata not found from parameters\"}", code))) + return } payload := make(map[string]interface{}, 0) err = json.Unmarshal(body, &payload) @@ -189,12 +203,13 @@ func (s ServerResource) EntityUpdateHandlerV1_1(w http.ResponseWriter, r *http.R metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } start := time.Now() - code := http.StatusOK defer func() { metrics.DgraphUpdateEntityLatencyHistogram.WithLabelValues(fmt.Sprintf("%d", code)).Observe(time.Since(start).Seconds()) }() @@ -203,13 +218,14 @@ func (s ServerResource) EntityUpdateHandlerV1_1(w http.ResponseWriter, r *http.R if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() - code = http.StatusInternalServerError log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + code = http.StatusInternalServerError + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "uid": uuid, diff --git a/service/server.go b/service/server.go index 452cee1..fd180bb 100644 --- a/service/server.go +++ b/service/server.go @@ -44,6 +44,7 @@ func serve() { qslSvc := apis.NewQSLService(dc) res := resources.ServerResource{EntitySvc: entitySvc, QuerySvc: querySvc, MetaSvc: metaSvc, QSLSvc: qslSvc} // Entity APIs v1 + router.HandleFunc("/v1/entity/{metadata}/{uid}", res.EntityGetHandler).Methods("GET") router.HandleFunc("/v1/entity/{metadata}", res.EntityCreateHandler).Methods("POST") router.HandleFunc("/v1/entity/{metadata}/{uid}", res.EntityUpdateHandler).Methods("POST") @@ -51,7 +52,7 @@ func serve() { router.HandleFunc("/v1/sync/{metadata}", res.EntitySyncHandler).Methods("POST") // Query APIs router.HandleFunc("/v1/query", res.QueryHandler).Methods("GET") - router.HandleFunc("/v1/qsl/{query}", res.QSLHandler).Methods("GET") + router.HandleFunc("/v1/qsl/{query:.*}", res.QSLHandler).Methods("GET") //Metadata router.HandleFunc("/v1/metadata/{name}", res.MetaGetHandler).Methods("GET") router.HandleFunc("/v1/metadata/{name}", res.MetaDeleteHandler).Methods("DELETE") @@ -68,7 +69,8 @@ func serve() { router.HandleFunc("/v1.1/sync/{metadata}", res.EntitySyncHandlerV1_1).Methods("POST") // Query APIs v1.1 router.HandleFunc("/v1.1/query", res.QueryHandlerV1_1).Methods("GET") - router.HandleFunc("/v1.1/qsl/{query}", res.QSLHandlerV1_1).Methods("GET") + // add .* to support url that contains special characters like pod[@name="abc/bcd"]{} + router.HandleFunc("/v1.1/qsl/{query:.*}", res.QSLHandlerV1_1).Methods("GET") //Metadata v1.1 router.HandleFunc("/v1.1/metadata/{name}", res.MetaGetHandlerV1_1).Methods("GET") router.HandleFunc("/v1.1/metadata/{name}", res.MetaDeleteHandlerV1_1).Methods("DELETE")