Skip to content

Dependency-free Express style http router written in go

License

Notifications You must be signed in to change notification settings

ferdiebergado/go-express

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-express

Simple, dependency-free, and Express-styled HTTP Router written in Go.

Features

  • Simple and easy to use
  • Expressjs-style routing
  • Relies only on the Go standard library
  • Uses net/http ServeMux under the hood
  • Static files handling
  • Common middlewares available out of the box

Requirements

  • Go 1.22 or higher

Installation

go get github.com/ferdiebergado/go-express

Usage

  1. Import the router.
import router "github.com/ferdiebergado/go-express"
  1. Create a router.
router := router.NewRouter()
  1. Register global middlewares.

Global middlewares are registered by calling the Use() method on the router.

router.Use(RequestLogger)

go-express has some commonly-used middlewares available out of the box, just import it from the middleware package.

import (
	"github.com/ferdiebergado/go-express/router"
	"github.com/ferdiebergado/go-express/middleware"
)

func main() {
	router := router.NewRouter()

	router.Use(middleware.RequestLogger)
	router.Use(middleware.StripTrailingSlashes)
	router.Use(middleware.PanicRecovery)
}
  1. Register routes.

Similar to express, the http methods are available as methods in the router. The method accepts the path and the handler as arguments.

router.Get(path, handler)

Example:

router.Get("/todos", TodoHandler)

The handler is a function that accepts an http.ResponseWriter and a pointer to an http.Request as arguments.

func Handler(w http.ResponseWriter, r *http.Request)

Example:

func TodoHandler(w http.ResponseWriter, r *http.Request) {
    w.write([]byte("Todos"))
}

Optionally, you can register path-specific middlewares by passing them as arguments after the handler.

router.Post("/todos", CreateTodoHandler, SessionMiddleware, AuthMiddleware)

In here, the route has two specific middlewares: SessionMiddleware and AuthMiddleware.

You can pass any number of middlewares to a route.

  1. Start an http server with the router.
http.ListenAndServe(":8080", router)

Serving Static Files

go-express makes it easy to serve static files from a specified directory. Simply provide the name of the directory containing the static files to be served to the ServeStatic method of the router.

router.ServeStatic("assets")

This will serve files from the "assets" directory at "/assets/". Now, any request the starts with /assets/ will serve files from this directory, e.g. /assets/styles.css.

You can then add this to the head tag of your html:

<head>
  <link rel="stylesheet" src="/assets/styles.css">
  <script src="/assets/js/app.js" defer>
</head>

Custom 404 Error Handler

By default, go-express returns a 404 status code and plain status text when an unregistered route is requested. To customize this behavior, pass an http handler function to the NotFound method of the router.

Example:

router.NotFound(func(w http.ResponseWriter, r *http.Request){
	templates := template.Must(template.ParseGlob("templates/*.html"))

	var buf bytes.Buffer

	if err := templates.ExecuteTemplate(&buf, "404.html", nil); err != nil {
    log.Prinf("execute template: %w", err)
		return
	}

	_, err = buf.WriteTo(w)

	if err != nil {
    log.Printf("write to buffer: %w", err)
		return
	}
})

Writing Middlewares

Middlewares are functions that accept an http.Handler and returns another http.Handler.

func Middleware(next http.Handler) http.Handler

Example:

func RequestLogger(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		next.ServeHTTP(w, r)
		duration := time.Since(start)
		log.Printf("%s %s %s %d", r.Method, r.URL.Path, r.Proto, duration)
	})
}

Complete Usage Example

package main

import (
	"net/http"

	router "github.com/ferdiebergado/go-express"
	"github.com/ferdiebergado/go-express/middleware"
)

func main() {

	// Create the router.
	router := router.NewRouter()

	// Register global middlewares.
	router.Use(middleware.RequestLogger)
	router.Use(middleware.StripTrailingSlashes)
	router.Use(middleware.PanicRecovery)

	// Serve static files.
	router.ServeStatic("assets")

	// Register routes.
	router.Get("/api/todos", ListTodos)
	router.Post("/api/todos", CreateTodo, AuthMiddleware)
	router.Put("/api/todos/{id}", UpdateTodo, AuthMiddleware)
	router.Delete("/api/todos/{id}", DeleteTodo, AuthMiddleware)

  // Start an http server with the router.
	http.ListenAndServe(":8080", router)
}

func ListTodos(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Todo list"))
}

func CreateTodo(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusCreated)
}

func UpdateTodo(w http.ResponseWriter, r *http.Request) {
	id := r.PathValue("id")

	w.Write([]byte("Todo with id "+id+" updated"))
}

func DeleteTodo(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNoContent)
}

func AuthMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		authHeader := r.Header.Get("Authorization")

		// Check for the Authorization header
		if authHeader == "" || authHeader != "Bearer valid-token" { // replace "valid-token" with actual validation logic
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}

		// Call the next handler in the chain
		next.ServeHTTP(w, r)
	})
}

License

go-express is open-sourced software licensed under MIT License.

About

Dependency-free Express style http router written in go

Resources

License

Stars

Watchers

Forks

Packages

No packages published