ex4api.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. Available routes:
  3. /api/users OPTIONS Expose available actions
  4. /api/users GET Return user list, possibly filtered
  5. /api/users POST Create user
  6. /api/users/123 GET Return user 123 -> not listed in book
  7. /api/users/123 PUT Update user 123
  8. /api/users/123 DELETE Delete user 123
  9. POST fields:
  10. "user" -> name
  11. "mail" -> email
  12. "first"
  13. "last"
  14. */
  15. package main
  16. import (
  17. "database/sql"
  18. "encoding/json"
  19. "fmt"
  20. "log"
  21. "net/http"
  22. _ "github.com/go-sql-driver/mysql"
  23. "github.com/gorilla/mux"
  24. )
  25. var database *sql.DB
  26. type Users struct {
  27. Users []User `json:"users"`
  28. }
  29. type User struct {
  30. ID int `json:"id"`
  31. Name string `json:"username"`
  32. Email string `json:"mail"`
  33. First string `json:"first"`
  34. Last string `json:"last"`
  35. }
  36. type CreateResponse struct {
  37. Error string `json:"error"`
  38. }
  39. /*
  40. UserCreate creates a new user and stores it.
  41. The SQL query is vulnerable to injection, so the route matching needs be safe.
  42. */
  43. func UserCreate(w http.ResponseWriter, r *http.Request) {
  44. w.Header().Set("Access-Control-Allow-Origin", "http://localhost:8000")
  45. NewUser := User{
  46. Name: r.FormValue("user"),
  47. Email: r.FormValue("mail"),
  48. First: r.FormValue("first"),
  49. Last: r.FormValue("last"),
  50. }
  51. output, err := json.MarshalIndent(NewUser, "", " ")
  52. fmt.Println(string(output))
  53. if err != nil {
  54. fmt.Println("Something went wrong!")
  55. }
  56. Response := CreateResponse{}
  57. sql := "INSERT INTO users SET user_name='" + NewUser.Name +
  58. "', user_first='" + NewUser.First +
  59. "', user_last='" + NewUser.Last +
  60. "', user_email='" + NewUser.Email + "'"
  61. result, err := database.Exec(sql)
  62. if err != nil {
  63. Response.Error = err.Error()
  64. }
  65. var id int64
  66. var rows int64
  67. createOutput, err := json.MarshalIndent(Response, "", " ")
  68. if result != nil {
  69. id, _ = result.LastInsertId()
  70. rows, _ = result.RowsAffected()
  71. } else {
  72. id = 0
  73. rows = 0
  74. fmt.Println(w, string(createOutput))
  75. }
  76. fmt.Printf("Id: %d, Rows affected: %d\n", id, rows)
  77. // createOutput, err := json.MarshalIndent(Response, "", " ")
  78. fmt.Fprintln(w, string(createOutput))
  79. }
  80. func UsersRetrieve(w http.ResponseWriter, r *http.Request) {
  81. w.Header().Set("Pragma", "no-cache")
  82. rows, err := database.Query(`
  83. SELECT u.user_id, u.user_name, u.user_email, u.user_first, u.user_last
  84. FROM users u
  85. LIMIT 10
  86. `)
  87. if err != nil {
  88. fmt.Fprintln(w, "Something went wrong!")
  89. log.Fatal(err)
  90. }
  91. Response := Users{}
  92. for rows.Next() {
  93. user := User{}
  94. rows.Scan(&user.ID, &user.Name, &user.Email, &user.First, &user.Last)
  95. Response.Users = append(Response.Users, user)
  96. }
  97. output, _ := json.MarshalIndent(Response, "", " ")
  98. fmt.Fprintln(w, string(output))
  99. }
  100. type API struct {
  101. Message string `json:"message"`
  102. }
  103. func UserMethods(w http.ResponseWriter, r *http.Request) {
  104. }
  105. func UserReplace(w http.ResponseWriter, r *http.Request) {
  106. }
  107. func UserDelete(w http.ResponseWriter, r *http.Request) {
  108. }
  109. func UserRetrieve(w http.ResponseWriter, r *http.Request) {
  110. w.Header().Set("Pragma", "no-cache")
  111. vars := mux.Vars(r)
  112. id := vars["id"]
  113. user := User{}
  114. var result API
  115. sqlQuery := `
  116. SELECT u.user_id, u.user_name, u.user_first, u.user_last, u.user_email
  117. FROM users u
  118. WHERE u.user_id = ?
  119. `
  120. stmt, err := database.Prepare(sqlQuery)
  121. if err != nil {
  122. log.Fatal(err.Error())
  123. }
  124. row := stmt.QueryRow(id)
  125. scanErr := row.Scan(&user.ID, &user.Name, &user.First, &user.Last, &user.Email)
  126. switch {
  127. case scanErr == sql.ErrNoRows:
  128. // FIXME XSS
  129. result = API{Message: fmt.Sprintf("No such user: %s", id)}
  130. json, err := json.MarshalIndent(result, "", " ")
  131. if err != nil {
  132. log.Fatal(err.Error())
  133. }
  134. w.Write(json)
  135. case err != nil:
  136. // FIXME XSS
  137. result = API{Message: fmt.Sprintf("Error reading user: %s", id)}
  138. json, errIndent := json.MarshalIndent(result, "", " ")
  139. if errIndent != nil {
  140. log.Fatal(errIndent.Error())
  141. }
  142. w.Write(json)
  143. log.Fatal(err.Error())
  144. case err == nil:
  145. json, errIndent := json.MarshalIndent(user, "", " ")
  146. if errIndent != nil {
  147. log.Fatal(errIndent.Error())
  148. }
  149. w.Write(json)
  150. }
  151. }
  152. func main() {
  153. var err error
  154. db, err := sql.Open("mysql", "goroot:gopass@/goweb_social_network")
  155. if err != nil {
  156. log.Fatal(err.Error())
  157. }
  158. database = db
  159. routes := mux.NewRouter()
  160. routes.HandleFunc("/api/users", UserCreate).Methods("POST")
  161. routes.HandleFunc(`/api/users`, UsersRetrieve).Methods("GET")
  162. // Not yet implemented.
  163. routes.HandleFunc(`/api/users`, UserMethods).Methods("OPTIONS")
  164. routes.HandleFunc(`/api/users/{id:[\d]+}`, UserRetrieve).Methods("GET")
  165. routes.HandleFunc(`/api/users/{id:[\d]+}`, UserReplace).Methods("PUT")
  166. routes.HandleFunc(`/api/users/{id:[\d]+}`, UserDelete).Methods("DELETE")
  167. // --------------------
  168. http.Handle("/", routes)
  169. http.ListenAndServe(":8080", nil)
  170. }