Skip to content

Instantly share code, notes, and snippets.

@zeyneloz
Last active September 25, 2019 09:19
Show Gist options
  • Save zeyneloz/64fe8d9291de8554147ae399acc20b83 to your computer and use it in GitHub Desktop.
Save zeyneloz/64fe8d9291de8554147ae399acc20b83 to your computer and use it in GitHub Desktop.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type loginSchema struct {
Username string `json:"username"`
Password string `json:"password"`
}
// Return `true`, nil if given user and password exists in database.
func loginUser(username string, password string) (bool, error) {...}
// Use as a wrapper around the handler functions.
type rootHandler func(http.ResponseWriter, *http.Request) error
func loginHandler(w http.ResponseWriter, r *http.Request) error {
if r.Method != http.MethodPost {
return NewHTTPError(nil, 405, "Method not allowed.")
}
body, err := ioutil.ReadAll(r.Body) // Read request body.
if err != nil {
return fmt.Errorf("Request body read error : %v", err)
}
// Parse body as json.
var schema loginSchema
if err = json.Unmarshal(body, &schema); err != nil {
return NewHTTPError(err, 400, "Bad request : invalid JSON.")
}
ok, err := loginUser(schema.Username, schema.Password)
if err != nil {
return fmt.Errorf("loginUser DB error : %v", err)
}
if !ok { // Authentication failed.
return NewHTTPError(nil, 401, "Wrong password or username.")
}
w.WriteHeader(200) // Successfully authenticated. Return access token?
return nil
}
// rootHandler implements http.Handler interface.
func (fn rootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := fn(w, r) // Call handler function
if err == nil {
return
}
// This is where our error handling logic starts.
log.Printf("An error accured: %v", err) // Log the error.
clientError, ok := err.(ClientError) // Check if it is a ClientError.
if !ok {
// If the error is not ClientError, assume that it is ServerError.
w.WriteHeader(500) // return 500 Internal Server Error.
return
}
body, err := clientError.ResponseBody() // Try to get response body of ClientError.
if err != nil {
log.Printf("An error accured: %v", err)
w.WriteHeader(500)
return
}
status, headers := clientError.ResponseHeaders() // Get http status code and headers.
for k, v := range headers {
w.Header().Set(k, v)
}
w.WriteHeader(status)
w.Write(body)
}
func main() {
// Notice rootHandler.
http.Handle("/login/", rootHandler(loginHandler))
log.Fatal(http.ListenAndServe(":8080", nil))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment