I'm in the process of making a simple REST API using Echo. I have a variable which is the following map, based on this struct I've made:
type Checklist struct {
ID int `json:"id"`
Title string `json:"title"`
Lines []string `json:"lines"`
AuthorName string `json:"authorName"`
AuthorID int `json:"authorID"`
Tags []Tag `json:"tags"`
}
var (
checklists = map[int]*Checklist{}
checklistSeq = 1
checklistLock = sync.Mutex{}
)
After creating a new checklist and appending it to the checklists variable, how can I send a request which appends a new line in the Lines field of the new checklist?
The solution I thought up was this:
func createChecklist(c echo.Context) error {
checklistLock.Lock()
defer checklistLock.Unlock()
newChecklist := &Checklist{
ID: checklistSeq,
Lines: make([]string, 0),
Tags: make([]Tag, 0),
}
if err := c.Bind(newChecklist); err != nil {
return err
}
checklists[newChecklist.ID] = newChecklist
checklistSeq++
return c.JSON(http.StatusOK, newChecklist)
}
func addLine(c echo.Context) error {
checklistLock.Lock()
defer checklistLock.Unlock()
id, _ := strconv.Atoi(c.Param("id"))
checklist := *checklists[id]
line := []string{""}
if err := c.Bind(line); err != nil {
return err
}
checklist.Lines = line
return c.JSON(http.StatusCreated, checklists)
}
However, when I test this handler, it gives me the following results:
// 1: Creating a new checklist
$ curl -X POST -H 'Content-Type: application/json' -d '{"title": "test"}' localhost:1234/checklist
>> {"id":1,"title":"test","lines":[],"authorName":"","authorID":0,"tags":[]}
// 2: Check to see the checklist has been created.
$ curl -X GET localhost:1234/checklist
>> {"1":{"id":1,"title":"test","lines":[],"authorName":"","authorID":0,"tags":[]}}
// 3: Attempting to create a new line
$ curl -X POST -H 'Content-Type: application/json' -d '{"lines": "test123"}' localhost:1234/checklist/1
>> curl: (52) Empty reply from server
// 4: Confirming it hasn't been created.
$ curl -X GET localhost:1234/checklist
>> {"1":{"id":1,"title":"test","lines":[],"authorName":"","authorID":0,"tags":[]}}
So the function doesn't actually work, since neither the expected response comes back from pinging the POST to the appropriate route or the line is actually added to the field.
func addLine(c echo.Context) error {
checklistLock.Lock()
defer checklistLock.Unlock()
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
return err
}
// do not deref *Checklist
cl, ok := checklists[id]
if !ok {
return echo.ErrNotFound
}
// use same structure as the expected JSON
var input struct { Lines []string `json:"lines"` }
// always pass a pointer to c.Bind
if err := c.Bind(&input); err != nil {
return err
}
// do not overwrite previously written lines, use append
cl.Lines = append(cl.Lines, input.Lines...)
return c.JSON(http.StatusOK, cl)
}
Now try:
$ curl -X POST -H 'Content-Type: application/json' -d '{"lines": ["test123"]}' localhost:1234/checklist/1
(notice that "test123"
is enclosed in brackets)