|
@@ -0,0 +1,191 @@
|
|
|
+/*
|
|
|
+Available routes:
|
|
|
+
|
|
|
+/api/users OPTIONS Expose available actions
|
|
|
+/api/users GET Return user list, possibly filtered
|
|
|
+/api/users POST Create user
|
|
|
+/api/users/123 GET Return user 123 -> not listed in book
|
|
|
+/api/users/123 PUT Update user 123
|
|
|
+/api/users/123 DELETE Delete user 123
|
|
|
+*/
|
|
|
+
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "database/sql"
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "log"
|
|
|
+ "net/http"
|
|
|
+ "net/url"
|
|
|
+ "strconv"
|
|
|
+
|
|
|
+ _ "github.com/go-sql-driver/mysql"
|
|
|
+
|
|
|
+ "github.com/gorilla/mux"
|
|
|
+)
|
|
|
+
|
|
|
+var database *sql.DB
|
|
|
+
|
|
|
+type Users struct {
|
|
|
+ Users []User `json:"users"`
|
|
|
+}
|
|
|
+
|
|
|
+type User struct {
|
|
|
+ ID int `json:"id"`
|
|
|
+ Name string `json:"username"`
|
|
|
+ Email string `json:"mail"`
|
|
|
+ First string `json:"first"`
|
|
|
+ Last string `json:"last"`
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+UserCreate creates a new user and stores it.
|
|
|
+
|
|
|
+The SQL query is vulnerable to injection, so the route matching needs be safe.
|
|
|
+*/
|
|
|
+func UserCreate(w http.ResponseWriter, r *http.Request) {
|
|
|
+ NewUser := User{
|
|
|
+ Name: r.FormValue("name"),
|
|
|
+ Email: r.FormValue("mail"),
|
|
|
+ First: r.FormValue("first"),
|
|
|
+ Last: r.FormValue("last"),
|
|
|
+ }
|
|
|
+
|
|
|
+ output, err := json.MarshalIndent(NewUser, "", " ")
|
|
|
+ fmt.Println(string(output))
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("Something went wrong!")
|
|
|
+ }
|
|
|
+
|
|
|
+ sql := "INSERT INTO user SET user_nickname='" + NewUser.Name +
|
|
|
+ "', user_first='" + NewUser.First +
|
|
|
+ "', user_last='" + NewUser.Last +
|
|
|
+ "', user_email='" + NewUser.Email + "'"
|
|
|
+ q, err := database.Exec(sql)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println(err)
|
|
|
+ }
|
|
|
+ fmt.Println(q)
|
|
|
+}
|
|
|
+
|
|
|
+func UsersRetrieve(w http.ResponseWriter, r *http.Request) {
|
|
|
+ w.Header().Set("Pragma", "no-cache")
|
|
|
+
|
|
|
+ start := 0
|
|
|
+ limit := 10
|
|
|
+
|
|
|
+ next := start + limit
|
|
|
+
|
|
|
+ requestUrl := r.URL
|
|
|
+ requestUrl.RawQuery = url.QueryEscape("start=" + strconv.Itoa(next) + "&foo=ba r")
|
|
|
+
|
|
|
+ w.Header().Set("Link", "<"+requestUrl.String()+">; rel=\"next\"")
|
|
|
+
|
|
|
+ rows, err := database.Query(`
|
|
|
+SELECT u.user_id, u.user_name, u.user_email, u.user_first, u.user_last
|
|
|
+FROM users u
|
|
|
+LIMIT 10
|
|
|
+ `)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Fprintln(w, "Something went wrong!")
|
|
|
+ log.Fatal(err)
|
|
|
+ }
|
|
|
+ Response := Users{}
|
|
|
+ for rows.Next() {
|
|
|
+ user := User{}
|
|
|
+ rows.Scan(&user.ID, &user.Name, &user.Email, &user.First, &user.Last)
|
|
|
+ Response.Users = append(Response.Users, user)
|
|
|
+ }
|
|
|
+
|
|
|
+ output, _ := json.MarshalIndent(Response, "", " ")
|
|
|
+ fmt.Fprintln(w, string(output))
|
|
|
+}
|
|
|
+
|
|
|
+type API struct {
|
|
|
+ Message string `json:"message"`
|
|
|
+}
|
|
|
+
|
|
|
+func UserMethods(w http.ResponseWriter, r *http.Request) {
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+func UserReplace(w http.ResponseWriter, r *http.Request) {
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+func UserDelete(w http.ResponseWriter, r *http.Request) {
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+func UserRetrieve(w http.ResponseWriter, r *http.Request) {
|
|
|
+ w.Header().Set("Pragma", "no-cache")
|
|
|
+
|
|
|
+ vars := mux.Vars(r)
|
|
|
+ id := vars["id"]
|
|
|
+ user := User{}
|
|
|
+ var result API
|
|
|
+
|
|
|
+ sqlQuery := `
|
|
|
+SELECT u.user_id, u.user_nickname, u.user_first, u.user_last, u.user_email
|
|
|
+FROM user u
|
|
|
+WHERE u.user_id = ?
|
|
|
+`
|
|
|
+ stmt, err := database.Prepare(sqlQuery)
|
|
|
+ if err != nil {
|
|
|
+ log.Fatal(err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ row := stmt.QueryRow(id)
|
|
|
+ scanErr := row.Scan(&user.ID, &user.Name, &user.First, &user.Last, &user.Email)
|
|
|
+ switch {
|
|
|
+ case scanErr == sql.ErrNoRows:
|
|
|
+ // FIXME XSS
|
|
|
+ result = API{Message: fmt.Sprintf("No such user: %s", id)}
|
|
|
+ json, err := json.MarshalIndent(result, "", " ")
|
|
|
+ if err != nil {
|
|
|
+ log.Fatal(err.Error())
|
|
|
+ }
|
|
|
+ w.Write(json)
|
|
|
+ case err != nil:
|
|
|
+ // FIXME XSS
|
|
|
+ result = API{Message: fmt.Sprintf("Error reading user: %s", id)}
|
|
|
+ json, errIndent := json.MarshalIndent(result, "", " ")
|
|
|
+ if errIndent != nil {
|
|
|
+ log.Fatal(errIndent.Error())
|
|
|
+ }
|
|
|
+ w.Write(json)
|
|
|
+ log.Fatal(err.Error())
|
|
|
+ case err == nil:
|
|
|
+ json, errIndent := json.MarshalIndent(user, "", " ")
|
|
|
+ if errIndent != nil {
|
|
|
+ log.Fatal(errIndent.Error())
|
|
|
+ }
|
|
|
+ w.Write(json)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func main() {
|
|
|
+ var err error
|
|
|
+
|
|
|
+ db, err := sql.Open("mysql", "goroot:gopass@/goweb_social_network")
|
|
|
+ if err != nil {
|
|
|
+ log.Fatal(err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ database = db
|
|
|
+
|
|
|
+ routes := mux.NewRouter()
|
|
|
+ routes.HandleFunc("/api/users", UserCreate).Methods("POST")
|
|
|
+ routes.HandleFunc(`/api/users`, UsersRetrieve).Methods("GET")
|
|
|
+
|
|
|
+ // Not yet implemented.
|
|
|
+ routes.HandleFunc(`/api/users`, UserMethods).Methods("OPTIONS")
|
|
|
+ routes.HandleFunc(`/api/users/{id:[\d]+}`, UserRetrieve).Methods("GET")
|
|
|
+ routes.HandleFunc(`/api/users/{id:[\d]+}`, UserReplace).Methods("PUT")
|
|
|
+ routes.HandleFunc(`/api/users/{id:[\d]+}`, UserDelete).Methods("DELETE")
|
|
|
+ // --------------------
|
|
|
+
|
|
|
+ http.Handle("/", routes)
|
|
|
+ http.ListenAndServe(":8080", nil)
|
|
|
+}
|