github.com/TheDeveloper10/rem

A powerful and very flexible HTTP router and URL matcher


Keywords
go, http, middleware, router, simple
License
MIT
Install
go get github.com/TheDeveloper10/rem

Documentation

TheDeveloper10/rem

Package TheDeveloper10/rem implements a request router and dispatcher for matching incoming requests to their respective handler.

The name REM comes from the state of sleep called REM. The same way sleep is a rest from engineering this package is a rest from swiss knife packages that solve all of your problems and create a thousand more.

The main features are:

  • It implements the http.Handler interface so it is compatible with net/http (this allows for use of other packages such as github.com/rs/cors)
  • Requests can be matched based on URL paths and HTTP Methods
  • URL paths can have optional variables


Install

With a correctly configured Go toolchain:

go get -u github.com/TheDeveloper10/rem@v1.1.1

Examples

This is a very simple example that describes the entire package really well. First we create a new rem.Router and then we use it to create new routes. The process of creating routes is really easy: we just use the Get for handling GET HTTP method, Post for handling POST HTTP method, etc. for the rest of the methods and then we assign the handlers that we want the data to go through.

In all of the cases in this example we go through AuthMiddleware. That's just a middleware used for authentication of the call. If the call passes through the AuthMiddleware it goes to the respective handler (e.g. GetProductsHandle).

func main() {
	// Create a new router
	router := rem.NewRouter()
	
	// Add a new route
	router.
		NewRoute("/products").
		Get(AuthMiddleware, GetProductsHandle).
		Post(AuthMiddleware, CreateProductsHandle)
	    
	
	// Add a new route
	router.
		NewRoute("/products/:productId").
		Get(AuthMiddleware, GetProductHandle).
		Put(AuthMiddleware, ReplaceProductHandle).
		Delete(AuthMiddleware, DeleteProductHandle)
	
	// Start the HTTP server
	http.ListenAndServe(":80", router)
}

Creating your own handlers:

type userResponse struct {
	id string `json:"id"`
}

func main() {
	router := rem.NewRouter()
	
	router.
		NewRoute("/users").
		Post(func(response rem.IResponse, request rem.IRequest) bool {
			request.
				Status(http.StatusCreated).
				JSON(useResponse{
					id: "jxIZp17"
				})
        
			// In case of a single handler it doesn't matter what you 
			// return (true or false). It only matters when there's more 
			// than one handler because that's how the route decides to 
			// continue passing to the next handler.
			return true
		})
}

Middlewares and handlers:

func AuthMiddleware(response rem.IResponse, request rem.IRequest) bool {
	authHeader, status := request.GetHeaders().Get("Authentication")
	if !status {
		response.Status(http.StatusUnauthorized)
		// Returning false means it will not continue to the next handler
		return false
	}
	
	// Obviously here you won't perform this type of authentication...
	if authHeader != "1234" {
		response.Status(http.StatusUnauthorized)
		return false
	}
	
	return true
}

func GetProductsHandler(response rem.IResponse, request rem.IRequest) bool {
	response.
		JSON([]Product{
			{ id: "nXJf", price: 39.99, name: "Super new shoes" },
			{ id: "zeq2", price: 1999.99, name: "Newest Phone" },
			{ id: "cv41", price: 4.99, name: "New headphones" },
		}).
		Status(http.StatusOK)
	
	return true
}

type Product struct {
	id    string
	price float32
	name  string
}

Path and Query parameters in URL:

type Product struct {
	Id    string  `json:"id"`
	Price float32 `json:"price"`
	Name  string  `json:"name"` 
}

func GetProductHandler(response rem.IResponse, request rem.IRequest) bool {
	productId, status1 := request.GetURLParameters().Get("productId")
	if !status1 {
		response.Status(http.StatusBadRequest)
	    return true	
    }
	
	priceStr, status2 := request.GetQueryParameters().Get("price")
	
	priceVal := 3.99
	if status2 {
		priceFloat, err := strconv.ParseFloat(priceStr, 64)
		if err == nil {
		    priceVal = float32(priceFloat)
		}
	}
	
	// e.g. for request GET /products/ZxF?price=40 the result will be:
	// { "id": "ZxF", "price": 40, "Name": "Some Name" }

	// and for request GET /products/qwe the result will be:
	// { "id": "qwe", "price": 3.99, "Name": "Some Name" }

	response.
		Status(http.StatusOK).
		JSON(Product{
		    Id: productId,
			Price: priceVal,
			Name: "Some name"
		})
	
	return true
}

func main() {
	router := rem.NewRouter()
	
	router.
		NewRoute("/products/:productId").
		Get(GetProductHandler)
	
	http.ListenAndServe(":80", router)
}