5api-link.go 4.2 KB

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