You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

331 lines
8.0 KiB

package api
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"git.tovijaeschke.xyz/tovi/JumboPetstore/database"
"git.tovijaeschke.xyz/tovi/JumboPetstore/models"
schema "github.com/Kangaroux/go-map-schema"
"github.com/gorilla/mux"
)
func deserialsePetJson(data []byte) (models.Pet, error) {
var (
petData models.Pet = models.Pet{}
jsonStructureTest map[string]interface{} = make(map[string]interface{})
jsonStructureTestResults *schema.CompareResults
err error
)
// Verify the JSON has the correct structure
json.Unmarshal(data, &jsonStructureTest)
jsonStructureTestResults, err = schema.CompareMapToStruct(
&petData,
jsonStructureTest,
&schema.CompareOpts{
ConvertibleFunc: CanConvert,
TypeNameFunc: schema.DetailedTypeName,
})
if err != nil {
return petData, err
}
if len(jsonStructureTestResults.MismatchedFields) > 0 {
fmt.Println(jsonStructureTestResults.MismatchedFields)
return petData, errors.New("MismatchedFields found when deserializing data")
}
if len(jsonStructureTestResults.MissingFields) > 0 {
fmt.Println(jsonStructureTestResults.MissingFields)
return petData, errors.New("MissingFields found when deserializing data")
}
// Deserialize the JSON into the struct
err = json.Unmarshal(data, &petData)
return petData, err
}
func genericJsonReturn(w http.ResponseWriter, code int, msg, typ string) {
var (
responseJsonMap map[string]interface{}
responseJson []byte
err error
)
responseJsonMap = make(map[string]interface{})
w.WriteHeader(code)
responseJsonMap["code"] = code
responseJsonMap["type"] = typ
responseJsonMap["message"] = msg
responseJson, err = json.MarshalIndent(responseJsonMap, "", " ")
if err != nil {
log.Printf("Error occured creating response: %s\n", err.Error())
}
w.Write(responseJson)
}
func PetHandlerCreateUpdate(w http.ResponseWriter, r *http.Request) {
var (
requestBody []byte
petData models.Pet
returnJson []byte
err error
)
log.Printf("Pet handler recieved %s request", r.Method)
requestBody, err = ioutil.ReadAll(r.Body)
if err != nil {
log.Printf("Error encountered reading POST body: %s\n", err.Error())
genericJsonReturn(w, 500, "An error occured", "unknown")
return
}
petData, err = deserialsePetJson(requestBody)
if err != nil {
log.Printf("Invalid data provided to pet POST API: %s\n", err.Error())
genericJsonReturn(w, 405, "Invalid data", "unknown")
return
}
switch r.Method {
case "POST":
petData, err = database.CreatePet(petData)
if err != nil {
panic(err)
}
break
case "PUT":
petData, err = database.UpdatePet(petData)
if err != nil {
panic(err)
}
break
}
returnJson, err = json.MarshalIndent(petData, "", " ")
if err != nil {
log.Printf("Error encountered when creating pet record: %s\n", err.Error())
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
// Return updated json
w.WriteHeader(http.StatusOK)
w.Write(returnJson)
}
func PetHandlerId(w http.ResponseWriter, r *http.Request) {
var (
petData models.Pet
urlVars map[string]string
returnJson []byte
notFoundJson map[string]interface{} = make(map[string]interface{})
id_str string
id int
ok bool
err error
)
urlVars = mux.Vars(r)
id_str, ok = urlVars["petId"]
if !ok {
log.Printf("Error encountered getting id\n")
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
id, err = strconv.Atoi(id_str)
if err != nil {
log.Printf("Error encountered converting id to string: %s\n", err.Error())
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
petData = database.GetPetById(id)
if petData.Id == 0 {
log.Printf("Could not find pet with id %d\n", id)
w.WriteHeader(http.StatusNotFound)
notFoundJson["code"] = 404
notFoundJson["type"] = "unknown"
notFoundJson["message"] = "not found"
returnJson, err = json.MarshalIndent(notFoundJson, "", " ")
w.Write(returnJson)
return
}
switch r.Method {
case "GET":
returnJson, err = json.MarshalIndent(petData, "", " ")
if err != nil {
log.Printf("Error encountered when creating pet record: %s\n", err.Error())
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
// Return updated json
w.WriteHeader(http.StatusOK)
w.Write(returnJson)
break
case "POST":
err = r.ParseForm()
if err != nil {
log.Printf("Error encountered parsing form: %s\n", err.Error())
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
if r.FormValue("name") != "" {
petData.Name = r.FormValue("name")
}
if r.FormValue("status") != "" {
petData.Status = r.FormValue("status")
}
_, err = database.UpdatePet(petData)
if err != nil {
log.Printf("Error updating pet: %s\n", err.Error())
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
break
case "DELETE":
log.Printf("Marking pet %d as deleted\n", id)
database.DeletePet(petData)
w.WriteHeader(http.StatusOK)
notFoundJson["code"] = 200
notFoundJson["type"] = "unknown"
notFoundJson["message"] = id_str
returnJson, err = json.MarshalIndent(notFoundJson, "", " ")
w.Write(returnJson)
break
}
}
func PetHandlerFindByStatus(w http.ResponseWriter, r *http.Request) {
var (
status string
petData []models.Pet
returnJson []byte
err error
)
status = r.URL.Query().Get("status")
if status != "available" && status != "pending" && status != "sold" {
log.Printf("Invalid status provided to /pet/findByStatus")
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
petData, err = database.GetPetsByStatus(status)
if err != nil {
log.Printf("An error occured in GetPetsByStatus")
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
returnJson, err = json.MarshalIndent(petData, "", " ")
if err != nil {
log.Printf("An error occured while serializing pet data to JSON")
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
w.Write(returnJson)
}
func PetHandlerUploadImage(w http.ResponseWriter, r *http.Request) {
var (
urlVars map[string]string
file multipart.File
handler *multipart.FileHeader
tempFile *os.File
nameSplit []string
fileBytes []byte
id_str string
id int
ok bool
err error
)
urlVars = mux.Vars(r)
id_str, ok = urlVars["petId"]
if !ok {
log.Printf("Error encountered getting id\n")
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
id, err = strconv.Atoi(id_str)
if err != nil {
log.Printf("Error encountered converting id to string: %s\n", err.Error())
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
fmt.Println(id)
// Upload 10Mb files
r.ParseMultipartForm(10 << 20)
file, handler, err = r.FormFile("file")
if err != nil {
log.Printf("Error retrieving file: %s\n", err.Error())
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - An error has occured\n"))
return
}
defer file.Close()
nameSplit = strings.Split(handler.Filename, ".")
tempFile, err = ioutil.TempFile("./uploads", "upload-*."+nameSplit[len(nameSplit)-1])
if err != nil {
fmt.Println(err)
return
}
defer tempFile.Close()
fileBytes, err = ioutil.ReadAll(file)
if err != nil {
fmt.Println(err)
return
}
tempFile.Write(fileBytes)
err = database.AddPhotoToPet(id, filepath.Base(tempFile.Name()))
if err != nil {
fmt.Println(err)
return
}
fmt.Fprintf(w, "Successfully Uploaded File\n")
}