github.com/mssola/todo@v0.0.0-20181029153210-d25348dc3f48/app/topics_api.go (about) 1 // Copyright (C) 2014-2017 Miquel Sabaté Solà <mikisabate@gmail.com> 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 package app 8 9 import ( 10 "encoding/json" 11 "fmt" 12 "log" 13 "net/http" 14 15 "github.com/gorilla/mux" 16 "github.com/mssola/todo/lib" 17 ) 18 19 // The parameters that be given through a request body. 20 type params struct { 21 Name string 22 Contents string 23 } 24 25 // Get the possible parameters from the given request. Note that it will only 26 // check for the "name" and "contents" parameters. 27 func getFromBody(req *http.Request) *params { 28 var p params 29 30 if req.Body == nil { 31 return nil 32 } 33 34 decoder := json.NewDecoder(req.Body) 35 if err := decoder.Decode(&p); err != nil { 36 return nil 37 } 38 return &p 39 } 40 41 // Safely render and send a JSON response with the given topic. This function 42 // should be called after performing some operation that might return an error. 43 // This error from the previous operation is the third parameter. The fourth 44 // parameter tells this function to generate the Markdown code for this topic. 45 func renderJSON(res http.ResponseWriter, topic *Topic, err error, md bool) { 46 // Try to render the given Topic. 47 if err == nil { 48 if md { 49 topic.RenderMarkdown() 50 } 51 if b, err := json.Marshal(topic); err == nil { 52 fmt.Fprint(res, string(b)) 53 res.Header().Set("Content-Type", "application/json") 54 return 55 } 56 } 57 58 // Render a generic error. 59 lib.JSONError(res) 60 } 61 62 // TopicsIndexJSON responds to: GET /topics. This will only be called when the 63 // user requested a JSON response. 64 func TopicsIndexJSON(res http.ResponseWriter, req *http.Request) { 65 var topics []Topic 66 if _, err := Db.Select(&topics, "select * from topics"); err != nil { 67 log.Printf("Could not fetch topics: %v", err) 68 } 69 b, _ := json.Marshal(topics) 70 res.Header().Set("Content-Type", "application/json") 71 fmt.Fprint(res, string(b)) 72 } 73 74 // TopicsCreateJSON responds to: POST /topics. This will only be called when 75 // the user requested a JSON response. 76 func TopicsCreateJSON(res http.ResponseWriter, req *http.Request) { 77 if p := getFromBody(req); p == nil { 78 lib.JSONError(res) 79 } else { 80 t, err := createTopic(p.Name) 81 renderJSON(res, t, err, false) 82 } 83 } 84 85 // TopicsShowJSON responds to: GET /topics/:id. This will only be called when 86 // the user requested a JSON response. 87 func TopicsShowJSON(res http.ResponseWriter, req *http.Request) { 88 var t Topic 89 p := mux.Vars(req) 90 err := Db.SelectOne(&t, "select * from topics where id=$1", p["id"]) 91 renderJSON(res, &t, err, true) 92 } 93 94 // TopicsUpdateJSON responds to: PUT/PATCH /topics/:id. This will only be 95 // called when the user requested a JSON response. 96 func TopicsUpdateJSON(res http.ResponseWriter, req *http.Request) { 97 var str, value string 98 var p *params 99 100 if p = getFromBody(req); p == nil { 101 lib.JSONError(res) 102 return 103 } 104 105 // Execute the update query. Depending on the given parameters this will be 106 // just a plain rename, or a full update. 107 if value = p.Name; value == "" { 108 str = "contents" 109 if value = p.Contents; value == "" { 110 lib.JSONError(res) 111 return 112 } 113 } else { 114 str = "name" 115 } 116 117 // And finally send the JSON response. 118 var t Topic 119 str = fmt.Sprintf("update topics set %v=$1 where id=$2 returning *", str) 120 err := Db.SelectOne(&t, str, value, mux.Vars(req)["id"]) 121 renderJSON(res, &t, err, true) 122 } 123 124 // TopicsDestroyJSON responds to: PUT/PATCH /topics/:id. This will only be 125 // called when the user requested a JSON response. 126 func TopicsDestroyJSON(res http.ResponseWriter, req *http.Request) { 127 p := mux.Vars(req) 128 results, err := Db.Exec("delete from topics where id=$1", p["id"]) 129 130 res.Header().Set("Content-Type", "application/json") 131 if err != nil { 132 fmt.Fprint(res, lib.Response{Error: "Could not remove topic"}) 133 } else if count, _ := results.RowsAffected(); count == 0 { 134 fmt.Fprint(res, lib.Response{Error: "Could not remove topic"}) 135 } else { 136 fmt.Fprint(res, lib.Response{Message: "Ok"}) 137 } 138 }