Skip to content

Latest commit

 

History

History
339 lines (266 loc) · 9.14 KB

README.md

File metadata and controls

339 lines (266 loc) · 9.14 KB

HutPlate

Build Status

HutPlate is a Library over your standard net/http library which makes your life easier.

It handles Authentication, Session, HTTP Error Handling, Flash Messages and Redirection. All these things are a breeze to do with HutPlate which usually takes a lot of your time.

Some examples:

// Use any router, also using hutplate.Handler is optional
router.Handle("/", hutplate.Handler(CreatePost))

func CreatePost(hp hutplate.Http) interface{} {
	if ! hp.Auth.Check() {
	    // Will redirect and set flash message in session
	    return hp.Response.Redirect("/login").With("notice", "You have to login first!")
	}
	
	// hutplate.Http extends http.Request, so everything is still there
	if err := createPost(hp.FormValue("content")); err =! nil {
	    // Will show a generic error message to user with 500 status.
	    //  You can also customize the behaviour
	    return err
	}
	
	// The http.ResponseWriter is also there
	hp.Response.Write([]byte("Success!"))
}

Table of Contents

Setup

Just go get:

go get github.com/usmanhalalit/hutplate

and import the package.

Configuration

The only mandatory configuration for HutPlate is that you let it know where to find your user (any database/datastore is fine). It will give you email or whatever you log your user in with, you just return that user's id and hashed password. For example, a GORM example would look like this:

hutplate.Config.GetUserWithCred = func(credential interface{}) (interface{}, string) {
    // credential will be email, username or whatever you log in with
    user := models.User{}
    db.Orm.Find(&user, "email='" + credential.(string) + "'")
    
    return user.ID, user.Password
}

Another highly recommended configuration is that you set a session secret key:

hutplate.Config.SessionSecretKey = "a_random_secret_key"

Creating a HutPlate Instance

HutPlate comes with an HTTP handler, which gives you some extra power. But it's optional to use. If you want to keep using the default handler then you just call hutplate.NewHttp and give it your Request and ResponseWriter. Here's how:

func MyHandler(w http.ResponseWriter, r *http.Request,) {
	hp := hutplate.NewHttp(w, r)
}

If you use the HutPlate handler, then it is even easier:

router.Handle("/", hutplate.Handler(CreatePost))

func CreatePost(hp hutplate.Http) interface{} {
	// hutplate.Http extends http.Request, so everything is still there
	// like hp.FormValue("content")

	// The http.ResponseWriter is also there
	hp.Response.Write([]byte("Success!"))
}

Authentication

Login

success, _ := hp.Auth.Login(email, password)

It will let you know if user logging in succeeded or not by returning true or false and if there is an error (in rare case) it'll be in the second return value.

Login requires you to store bcrypt hashed password when you register/save your user. Here is an example of how you hash you password using bcrypt

hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), 14)

Check if Logged In

hp.Auth.Check()

Will return true or false.

Get Logged in User ID

hp.Auth.UserId()

Get the Logged in User

It gives you the whole user object, not just id. To use this feature, you need to set a configuration to let HutPlate know how to get the user from your database/datastore.

user, err = hp.Auth.User()

Configuration

hutplate.Config.GetUserWithId = func(userId interface{}) interface {} {
    // You will receive the userId just return the user with corresponding id  
}

A GORM example:

hutplate.Config.GetUserWithId = func(userId interface{}) interface {} {
    user := models.User{}
    if userId == nil {
        return user
    }
    db.Orm.Find(&user, userId)
    return user
}

Logout

hp.Auth.Logout()

HutPlate HTTP Handler

HutPlate also comes with an HTTP handler, using it is optional but you get so much power by using it.

  • It automatically creates an HutPlate instance for you.
  • You can return an error from the handler, so you do much less if err != nil.
  • You can configure how to handle all errors or group of errors. There is a sensible default.
  • You can return a Redirect or a plain string response (text, HTML, etc.).
// Use any router
router.Handle("/", hutplate.Handler(CreatePost))

func CreatePost(hp hutplate.Http) interface{} {
	if ! hp.Auth.Check() {
	    // Will redirect and set flash message in session
	    return hp.Response.Redirect("/login").With("notice", "You have to login first!")
	}
	
	// hutplate.Http extends http.Request, so everything is still there
	if err := createPost(hp.FormValue("content")); err =! nil {
	    // Will show a generic error message to user with 500 status.
	    //  You can also customize the behaviour
	    return err
	}
	
	// The http.ResponseWriter is also there
	hp.Response.Write([]byte("Success!"))
}

Configure the error handler

hutplate.Config.ErrorHandler = func(err error, hut hutplate.Http) {
        // TODO log the error
		http.Error(hut.Response, err.Error(), 404)
}

Redirect

// Plain redirect
hp.Response.Redirect("/admin")

// Redirect with a flash message
hp.Response.Redirect("/login").With("error", "Please do login!")

// Redirect with a different status code
hp.Response.Redirect("/login", 301)

Session

Set a session value and it will persist.

err := hp.Session.Set("test_key", "test_value")

Get the session value

err := hp.Session.Get("test_key")

Flash Messages

err = hut.Session.SetFlash("test_key", "value")

Getting a flash message is same as getting normal session value:

err := hp.Session.Get("test_key")

As mentioned above you can also easily set a flash message while you redirect.

Session Config

Storage Path

By default Session uses file system storage. You can optionally configure the storage directory by setting:

hutplate.Config.SessionDirectory = "path/to/dir"

By default it uses operating system's temp directory.

Secret Key

It is recommended that you set a session secret key by setting:

hutplate.Config.SessionSecretKey = "your_key"

Configure Session Store

As noted above, by default Session uses file system storage. But you can use an entire different session storage system. HutPlate uses Gorilla Sessions. So you can use any session storage supported by Gorilla Sessions, i.e. the store that implements Gorilla's sessions.Store interface.

Here is a list of session stores supported by Gorilla Sessions.

To use your own session store, use the SessionStore config, for example:

import "github.com/gorilla/sessions"
hutplate.Config.SessionStore = sessions.NewCookieStore(...)

Clear Context

Important Note: If you aren't using gorilla/mux router, you need to wrap your handlers with context.ClearHandler as or else you will leak memory! An easy way to do this is to wrap the top-level mux when calling http.ListenAndServe:

	http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))

The ClearHandler function is provided by the gorilla/context package.

More examples are available on the Gorilla website.

List of Config

hutplate.Config.GetUserWithId = func(userId interface{}) interface {} {

}

hutplate.Config.GetUserWithCred = func(credential interface{}) (interface{}, string) {
    
}

hutplate.Config.ErrorHandler = func(err error, hp hutplate.Http) {

}

hutplate.Config.SessionSecretKey = "a_secret_key"
hutplate.Config.SessionDirectory = "path/to/dir"

© 2020 Muhammad Usman. Licensed under MIT license.