michi

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 18, 2024 License: MIT Imports: 3 Imported by: 2

README

michi

michi is a true 100% compatible with net/http router for Go web applications.

Go Reference Go Report Card MIT Code size

Features

  • True 100% compatible with net/http - http.ServerMux, http.Handler and http.HandlerFunc
  • Enhanced http.ServeMux - After Go 1.22, it is possible to use http method and path values
  • API like chi - Route, Group, With and middlewares
  • No external dependencies - Only use standard package
  • Lightweight - Only 160 lines
  • Performance - Fast michi == http.ServeMux

Why michi?

After Go 1.22, HTTP routing in the standard library is now more expressive. The patterns used by net/http.ServeMux have been enhanced to accept methods and wildcards. But these were already in 3rd party Routing libraries. So, we removed these overlapping features and provide a lack of http.ServeMux features.

About michi(道)

  • michi(道) means routes in Japanese.

Getting Started

go get -u github.com/go-michi/michi
package main

import (
  "fmt"
  "net/http"

  "github.com/go-chi/chi/v5/middleware"
  "github.com/go-michi/michi"
)

func main() {
  r := michi.NewRouter()
  r.Use(middleware.Logger)
  r.HandleFunc("POST /a/{id}/{$}", func(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Hello " + req.PathValue("id")))
  })
  http.ListenAndServe(":3000", r)
}

Before using michi, read the http.ServeMux GoDoc. For more detailed usage, check the Example in michi GoDoc.

Migrating to michi(http.ServeMux) from chi

There are several changes, but rather than changing from chi to michi, it's about changing from chi to http.ServeMux. Therefore, what you need to understand is how to use the standard library's http.ServeMux, and the knowledge specific to michi is kept to a minimum.

import michi package

This change is due to michi.

- import  "github.com/go-chi/chi"
+ import  "github.com/go-michi/michi"

func main() {
-   r := chi.NewRouter()
+   r := michi.NewRouter()
}

Use Handle or HandleFunc method instead of Get, Post, Put, Delete, Patch, Options, Head method

This change is due to http.ServeMux.

func main() {
-   r.Get("/user/{id}", userHandler)
+   r.HandleFunc("GET /user/{id}", userHandler)
}

Use http.Request.PathValue method

This change is due to http.ServeMux.

func Handler(w http.ResponseWriter, r *http.Request) {
-   id := chi.URLParam(r, "id")
+   id := r.PathValue("id")
}

Use {$} suffix for exact match

This change is due to http.ServeMux.

  • with {$}, routing pattern match rule is same as chi
    • /a/{$} matches request /a/
  • without {$}, routing pattern match rule is same as old http.ServeMux
    • /a/ matches request /a/ and /a/b
func main() {
-   r.Handle("/a/", userHandler)
+   r.Handle("/a/{$}", userHandler)
}

Sub Router

This change is due to http.ServeMux. http.ServeMux doesn't have Mount method, use Handle method instead of Mount method. Handle method can't omit parent path.

// chi
func main() {
   r := chi.NewRouter()
   // omit /a/ path
   r.Handle("/hello", handler("hello"))
   r2 := chi.NewRouter()
   r2.Mount("/a", r)
 }
// michi
func main() {
    r := michi.NewRouter()
    // can't omit /a/ path
    r.Handle("/a/hello", handler("hello"))
    r2 := michi.NewRouter()
    r2.Handle("/a/", r)
}
func main() {
-   r.Handle("/hello", handler("hello"))
+   r.Handle("/a/hello", handler("hello"))
-   r2.Mount("/a", r)
+   r2.Handle("/a/", r)
 }

or using Route

// michi
func main() {
    r := michi.NewRouter()
    // can't omit /a/ path
    r.Route("/a", func(r michi.Router) {
        r.Handle("/hello", handler("hello"))
    })
}

Support version

michi only supports Go 1.22 or later and the two latest versions. Currently, supports Go 1.22.

Reference

Credits

Documentation

Overview

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/go-michi/michi"
)

func main() {
	h := func(name string) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Println(name + " handler")
		})
	}
	mid := func(name string) func(next http.Handler) http.Handler {
		return func(next http.Handler) http.Handler {
			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				fmt.Println(name + " start")
				next.ServeHTTP(w, r)
				fmt.Println(name + " end")
			})
		}
	}
	r := michi.NewRouter()
	r.Use(mid("a"))
	r.Handle("/a/", h("a"))
	r.Route("/b/", func(r *michi.Router) {
		r.Use(mid("b"))
		r.Handle("/", h("b"))
		r.With(mid("c1")).Handle("/c1/", h("c1"))
		r.Group(func(r *michi.Router) {
			r.Use(mid("c2"))
			r.Handle("/c2/", h("c2"))
		})
	})
	{
		w := httptest.NewRecorder()
		target := "https://example.com/a/"
		req := httptest.NewRequest(http.MethodPost, target, nil)
		fmt.Println(target)
		r.ServeHTTP(w, req)
		fmt.Println()
	}
	{
		w := httptest.NewRecorder()
		target := "https://example.com/b/"
		req := httptest.NewRequest(http.MethodPost, target, nil)
		fmt.Println(target)
		r.ServeHTTP(w, req)
		fmt.Println()
	}
	{
		w := httptest.NewRecorder()
		target := "https://example.com/b/c1/"
		req := httptest.NewRequest(http.MethodPost, target, nil)
		fmt.Println(target)
		r.ServeHTTP(w, req)
		fmt.Println()
	}
	{
		w := httptest.NewRecorder()
		target := "https://example.com/b/c2/"
		req := httptest.NewRequest(http.MethodPost, target, nil)
		fmt.Println(target)
		r.ServeHTTP(w, req)
		fmt.Println()
	}
}
Output:

https://example.com/a/
a start
a handler
a end

https://example.com/b/
a start
b start
b handler
b end
a end

https://example.com/b/c1/
a start
b start
c1 start
c1 handler
c1 end
b end
a end

https://example.com/b/c2/
a start
b start
c2 start
c2 handler
c2 end
b end
a end

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Router

type Router struct {
	// contains filtered or unexported fields
}

Router is a http.Handler

func NewRouter

func NewRouter() *Router

NewRouter creates a new Router

func (*Router) Group

func (r *Router) Group(fn func(sub *Router))

Group creates a new inline-Mux with a copy of middleware stack. It's useful for a group of handlers along the same routing path that use an additional

func (*Router) Handle

func (r *Router) Handle(pattern string, handler http.Handler)

Handle adds the route `pattern` that matches any http method to execute the `handler` http.Handler.

func (*Router) HandleFunc

func (r *Router) HandleFunc(pattern string, handlerFunc http.HandlerFunc)

HandleFunc adds the route `pattern` that matches any http method to execute the `handlerFn` http.HandlerFunc.

func (*Router) Route

func (r *Router) Route(pattern string, fn func(sub *Router))

Route creates a new Mux and mounts it along the `pattern` as a subrouter.

func (*Router) ServeHTTP

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP is the single method of the http.Handler interface that makes Mux interoperable with the standard library.

func (*Router) Use

func (r *Router) Use(middlewares ...func(http.Handler) http.Handler)

Use appends a middleware handler to the Mux middleware stack.

The middleware stack for any Mux will execute before searching for a matching route to a specific handler, which provides opportunity to respond early, change the course of the request execution, or set request-scoped values for the next http.Handler.

func (*Router) With

func (r *Router) With(middlewares ...func(http.Handler) http.Handler) *Router

With adds inline middlewares for an endpoint handler.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL