I’ve the below code:
package main
import (
"encoding/json"
"fmt"
"net/http"
"strings"
)
type user struct {
ID string `json:"id"`
Name string `json:"name"`
}
type response struct {
MsgType string `json:"type"`
MsgDeatial string `json:"details"`
}
func main() {
url := "http://localhost/users/1"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
var r response
if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
fmt.Println(err)
return
}
fmt.Println(r.MsgDeatial)
var u user // u := user{}
err := json.Unmarshal([]byte(r.MsgDeatial), &u)
if err != nil {
fmt.Println(err.Error())
return
}
reader := strings.NewReader(r.MsgDeatial)
if err := json.NewDecoder(reader).Decode(&u); err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(u.ID)
fmt.Println(u.Name)
}
That is recieving a json like:
{
"type": "Success",
"details": "{ID:\"1\", Name:\"bob\"}"
}
But the output I’m getting is:
{ID:"1", Name:"bob"}
invalid character 'I' looking for beginning of object key string
invalid character 'I' looking for beginning of object key string
The server API is:
package main
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"regexp"
"strings"
"sync"
)
var (
listUserRe = regexp.MustCompile(`^\/users[\/]*$`)
getUserRe = regexp.MustCompile(`^\/users\/(\d+)$`)
createUserRe = regexp.MustCompile(`^\/users[\/]*$`)
)
type user struct {
ID string `json:"id"`
Name string `json:"name"`
}
type response struct {
MsgType string `json:"type"`
MsgDeatial string `json:"details"`
}
type datastore struct {
m map[string]user
*sync.RWMutex
}
type userHandler struct {
store *datastore
}
func (h *userHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "application/json")
switch {
case r.Method == http.MethodGet && listUserRe.MatchString(r.URL.Path):
h.List(w, r)
return
case r.Method == http.MethodGet && getUserRe.MatchString(r.URL.Path):
h.Get(w, r)
return
case r.Method == http.MethodPost && createUserRe.MatchString(r.URL.Path):
h.Create(w, r)
return
default:
notFound(w, r)
return
}
}
func (h *userHandler) List(w http.ResponseWriter, r *http.Request) {
h.store.RLock()
users := make([]user, 0, len(h.store.m))
for _, v := range h.store.m {
users = append(users, v)
}
h.store.RUnlock()
jsonBytes, err := json.Marshal(users)
if err != nil {
internalServerError(w, r)
return
}
w.WriteHeader(http.StatusOK)
w.Write(jsonBytes)
}
func (h *userHandler) Get(w http.ResponseWriter, r *http.Request) {
matches := getUserRe.FindStringSubmatch(r.URL.Path)
if len(matches) < 2 {
notFound(w, r)
return
}
h.store.RLock()
u, ok := h.store.m[matches[1]]
h.store.RUnlock()
if !ok {
w.WriteHeader(http.StatusNotFound)
//w.Write([]byte("user not found"))
myJsonString := response{
MsgType: "Error",
MsgDeatial: "user not found",
}
jsonBytes, err := json.Marshal(myJsonString)
if err != nil {
internalServerError(w, r)
return
}
w.Write(jsonBytes)
return
}
w.WriteHeader(http.StatusOK)
fmt.Printf("%#v\n", u) // => main.user{ID:"1", Name:"bob"} // include the field names, and the struct type
fmt.Printf("%+v\n", u) // => {ID:1 Name:bob} // include the field names, but not the struct type
fmt.Printf("%v\n", u) // => {1 bob}
x := fmt.Sprintf("%v", strings.Trim(fmt.Sprintf("%#v", u), fmt.Sprintf("%+v", reflect.TypeOf(u))))
myJsonString := response{
MsgType: "Success",
MsgDeatial: x,
}
jsonBytes, err := json.Marshal(myJsonString)
if err != nil {
internalServerError(w, r)
return
}
w.Write(jsonBytes)
}
func (h *userHandler) Create(w http.ResponseWriter, r *http.Request) {
var u user
if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
internalServerError(w, r)
return
}
h.store.Lock()
h.store.m[u.ID] = u
h.store.Unlock()
myJsonString := response{
MsgType: "Success",
MsgDeatial: "User " + u.Name + " had been added",
}
jsonBytes, err := json.Marshal(myJsonString)
if err != nil {
internalServerError(w, r)
return
}
w.Write(jsonBytes)
}
func internalServerError(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("internal server error"))
}
func notFound(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("not found"))
}
func main() {
mux := http.NewServeMux()
userH := &userHandler{
store: &datastore{
m: map[string]user{
"1": {ID: "1", Name: "bob"},
},
RWMutex: &sync.RWMutex{},
},
}
mux.Handle("/users", userH)
mux.Handle("/users/", userH)
http.ListenAndServe("localhost:80", mux)
}
I do not think there is an error at the server code but I’m sharing it in case it was required.