Completing the CRUD for the query API. Also being able to execute a saved query.
TODO: Handle parameters while executing a saved query.
This commit is contained in:
parent
b38df1c07d
commit
ce34ff4a83
|
|
@ -2,15 +2,31 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ApiError struct {
|
||||
Code int64 `json:"code,omitempty"`
|
||||
Msg string `json:"msg,omitempty"`
|
||||
}
|
||||
|
||||
// HandleAPIError handles any error that bubbles up to the controller layer
|
||||
// TODO: Make the error generic enough with HTTP status codes and messages as well
|
||||
func HandleAPIError(w http.ResponseWriter, r *http.Request, err error) {
|
||||
// Write content-type, statuscode, payload
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(500)
|
||||
fmt.Fprintf(w, "%s", err)
|
||||
fmt.Fprintf(w, "%s", createErrorBody(err))
|
||||
}
|
||||
|
||||
func createErrorBody(err error) []byte {
|
||||
apiError := ApiError{
|
||||
Code: -1,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
|
||||
errorJSON, _ := json.Marshal(apiError)
|
||||
return errorJSON
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,83 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"internal-tools-server/models"
|
||||
"internal-tools-server/services"
|
||||
"net/http"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
/*
|
||||
This file contains the APIs for the client to invoke in order to fetch data or perform an action
|
||||
on the middleware server
|
||||
*/
|
||||
|
||||
// PostQuery executes a custom sql query on the client database
|
||||
func PostQuery(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
queryBody := models.ExecQuery{}
|
||||
err := json.NewDecoder(r.Body).Decode(&queryBody)
|
||||
if err != nil {
|
||||
HandleAPIError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
var mapArray []map[string]interface{}
|
||||
mapArray, err = services.ExecuteQuery(queryBody)
|
||||
if err != nil {
|
||||
HandleAPIError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Write content-type, statuscode, payload
|
||||
mapJSON, _ := json.Marshal(mapArray)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
fmt.Fprintf(w, "%s", mapJSON)
|
||||
}
|
||||
|
||||
// CreateQuery creates a new query for the user in the table
|
||||
func CreateQuery(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
queryBody := models.Query{}
|
||||
err := json.NewDecoder(r.Body).Decode(&queryBody)
|
||||
if err != nil {
|
||||
HandleAPIError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
queryBody, err = services.CreateQuery(queryBody)
|
||||
if err != nil {
|
||||
HandleAPIError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Write content-type, statuscode, payload
|
||||
queryJSON, _ := json.Marshal(queryBody)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
fmt.Fprintf(w, "%s", queryJSON)
|
||||
}
|
||||
|
||||
// UpdateQuery updates a given query in the database for a given account
|
||||
func UpdateQuery(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
queryBody := models.Query{}
|
||||
err := json.NewDecoder(r.Body).Decode(&queryBody)
|
||||
if err != nil {
|
||||
HandleAPIError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
queryBody, err = services.UpdateQuery(queryBody)
|
||||
if err != nil {
|
||||
HandleAPIError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Write content-type, statuscode, payload
|
||||
queryJSON, _ := json.Marshal(queryBody)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
fmt.Fprintf(w, "%s", queryJSON)
|
||||
}
|
||||
|
|
|
|||
29
app/server/src/models/query.go
Normal file
29
app/server/src/models/query.go
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package models
|
||||
|
||||
type (
|
||||
Query struct {
|
||||
ID int64 `json:"id" sql:"id"`
|
||||
Name string `json:"name" sql:"name"`
|
||||
QueryType string `json:"query_type,omitempty" sql:"query_type"`
|
||||
Executable string `json:"executable,omitempty" sql:"executable"`
|
||||
ResourceName string `json:"resource_name,omitempty" sql:"resource_name"`
|
||||
ConfirmationMsg string `json:"confirmation_msg,omitempty" sql:"confirmation_msg"`
|
||||
}
|
||||
|
||||
ExecQuery struct {
|
||||
QueryType string `json:"query_type,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Params Params `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
Params struct {
|
||||
QueryParams []KeyValue `json:"query_params,omitempty"`
|
||||
HeaderParams []KeyValue `json:"header_params,omitempty"`
|
||||
CookieParams []KeyValue `json:"cookie_params,omitempty"`
|
||||
}
|
||||
|
||||
KeyValue struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
)
|
||||
|
|
@ -47,7 +47,9 @@ func intializeServer() *httprouter.Router {
|
|||
// Page CRUD Endpoints
|
||||
|
||||
// Query CRUD Endpoints
|
||||
|
||||
router.POST(baseURL+apiVersion+url.QueryURL+"/execute", api.PostQuery)
|
||||
router.POST(baseURL+apiVersion+url.QueryURL, api.CreateQuery)
|
||||
router.PUT(baseURL+apiVersion+url.QueryURL, api.UpdateQuery)
|
||||
return router
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +78,7 @@ func runMigrations() {
|
|||
&models.User{},
|
||||
&models.Role{},
|
||||
&models.Page{},
|
||||
&models.Query{},
|
||||
)
|
||||
log.Println("Successfully run all migrations")
|
||||
}
|
||||
|
|
|
|||
54
app/server/src/services/query.go
Normal file
54
app/server/src/services/query.go
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"internal-tools-server/models"
|
||||
"internal-tools-server/storage"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// ExecuteQuery runs a custom SQL query on the client database
|
||||
func ExecuteQuery(queryBody models.ExecQuery) ([]map[string]interface{}, error) {
|
||||
if queryBody.QueryType == "sql" {
|
||||
// Get the actual query from the DB
|
||||
datastore := storage.StorageEngine.GetDatastore()
|
||||
queryDAO := &models.Query{}
|
||||
|
||||
if err := datastore.Where("name = ?", queryBody.Name).First(queryDAO).Error; gorm.IsRecordNotFoundError(err) {
|
||||
return nil, fmt.Errorf("Invalid queryName: %s provided", queryBody.Name)
|
||||
}
|
||||
|
||||
queryStr := queryDAO.Executable
|
||||
mapArray, err := storage.StorageEngine.ExecuteQuery(queryStr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapArray, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("QueryType: %s not supported", queryBody.QueryType)
|
||||
}
|
||||
|
||||
// CreateQuery creates a new query that can be executed by name at runtime
|
||||
func CreateQuery(queryBody models.Query) (models.Query, error) {
|
||||
datastore := storage.StorageEngine.GetDatastore()
|
||||
if err := datastore.Create(&queryBody).Error; err != nil {
|
||||
return models.Query{}, err
|
||||
}
|
||||
|
||||
return queryBody, nil
|
||||
}
|
||||
|
||||
// UpdateQuery updates an existing query in the database
|
||||
func UpdateQuery(query models.Query) (models.Query, error) {
|
||||
datastore := storage.StorageEngine.GetDatastore()
|
||||
|
||||
// Update only the non-nil values in the struct
|
||||
datastore.Model(&query).Updates(query)
|
||||
|
||||
// Select the updated record to return back to the client
|
||||
datastore.First(&query)
|
||||
return query, nil
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
package url
|
||||
|
||||
const ComponentURL = "/components"
|
||||
const QueryURL = "/query"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user