Skip to content

Instantly share code, notes, and snippets.

@mnbbrown
Last active December 18, 2015 13:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mnbbrown/5793883 to your computer and use it in GitHub Desktop.
Save mnbbrown/5793883 to your computer and use it in GitHub Desktop.
Go implementation of a JSON consuming RESTful API.

The following is a very barebones PoC implementation of a somewhat RESTful (more CRUD) API that consumes JSON. It's a WIP.

The GenUUID function is based upon nu7hatch's implementation: https://github.com/nu7hatch/gouuid

Things to improve:

  • Error and panic handling/recovery including the JSON marshalling of errors.
  • Persistance & Concurrency Locks
  • Logging
package main
import (
"crypto/rand"
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"net/http"
)
type Employee struct {
UUID string `json:"uuid"`
Name string `json:"name"`
Position string `json:"position"`
}
var employees map[string]*Employee
func HandleEmployee(rw http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
switch req.Method {
case "GET": //READ employee
fmt.Println("GET /employees/" + vars["uuid"])
employee := employees[vars["uuid"]]
js, err := json.Marshal(employee)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
SendJSON(rw, string(js))
return
case "PUT": // UPDATE employee
fmt.Println("PUT /employees/" + vars["uuid"])
employee := employees[vars["uuid"]]
dec := json.NewDecoder(req.Body)
err := dec.Decode(&employee)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
if employee.UUID != vars["uuid"] && employee.UUID != "" {
http.Error(rw, "UUID should not be sent in the request body", http.StatusBadRequest)
return
}
employee.UUID = vars["uuid"] // Ensure UUID is not changed with request
retjs, err := json.Marshal(employee)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
SendJSON(rw, string(retjs))
case "DELETE": // DELETE employee
fmt.Println("DELETE /employees/" + vars["uuid"])
delete(employees, vars["uuid"])
fmt.Fprint(rw, "Success")
}
}
func HandleEmployees(rw http.ResponseWriter, req *http.Request) {
switch req.Method {
case "GET": // INDEX employees
fmt.Println("GET /employees/")
var arr []*Employee
for _, v := range employees {
arr = append(arr, v)
}
js, err := json.Marshal(arr)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
SendJSON(rw, string(js))
case "POST": // CREATE employee
fmt.Println("POST /employees/")
employee := new(Employee)
employee.UUID = GenUUID()
dec := json.NewDecoder(req.Body)
err := dec.Decode(&employee)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
employees[employee.UUID] = employee
retjs, err := json.Marshal(employee)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
SendJSON(rw, string(retjs))
}
}
func SendJSON(rw http.ResponseWriter, content string) {
rw.Header().Set("Content-Type", "application/json; charset=utf-8")
fmt.Fprint(rw, content)
}
func GenUUID() string {
uuid := make([]byte, 16)
_, err := rand.Read(uuid[:])
if err != nil {
fmt.Println(err)
}
uuid[8] = (uuid[8] | 0x40) & 0x7F
uuid[6] = (uuid[6] & 0xF) | (4 << 4)
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:])
}
func main() {
employees = map[string]*Employee{
"abcde": &Employee{UUID: "abcde", Name: "Matthew Brown", Position: "Gopher"},
"xyz": &Employee{UUID: "xyz", Name: "Alexander Brown", Position: "Gopher's Assistant"},
}
router := mux.NewRouter()
router.HandleFunc("/employees/{uuid}", HandleEmployee)
router.HandleFunc("/employees", HandleEmployees)
http.ListenAndServe(":8080", router)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment