Giter Site home page Giter Site logo

bnkamalesh / webgo Goto Github PK

View Code? Open in Web Editor NEW
295.0 13.0 30.0 423 KB

A microframework to build web apps; with handler chaining, middleware support, and most of all; standard library compliant HTTP handlers(i.e. http.HandlerFunc).

License: MIT License

Go 93.63% CSS 0.71% HTML 2.41% JavaScript 3.26%
golang go web-framework api-server api-rest middleware webframework multiplexer awesome-go router

webgo's Introduction

webgo gopher

coverage

WebGo v7.0.0

WebGo is a minimalistic router for Go to build web applications (server side) with no 3rd party dependencies. WebGo will always be Go standard library compliant; with the HTTP handlers having the same signature as http.HandlerFunc.

Contents

  1. Router
  2. Handler chaining
  3. Middleware
  4. Error handling
  5. Helper functions
  6. HTTPS ready
  7. Graceful shutdown
  8. Logging
  9. Server-Sent Events
  10. Usage

Router

Webgo has a simplistic, linear path matching router and supports defining URIs with the following patterns

  1. /api/users - URI with no dynamic values
  2. /api/users/:userID
    • URI with a named parameter, userID
    • If TrailingSlash is set to true, it will accept the URI ending with a '/', refer to sample
  3. /api/users/:misc*
    • Named URI parameter misc, with a wildcard suffix '*'
    • This matches everything after /api/users. e.g. /api/users/a/b/c/d

When there are multiple handlers matching the same URI, only the first occurring handler will handle the request. Refer to the sample to see how routes are configured. You can access named parameters of the URI using the Context function.

Note: webgo Context is not available inside the special handlers (not found & method not implemented)

func helloWorld(w http.ResponseWriter, r *http.Request) {
	// WebGo context
	wctx := webgo.Context(r)
	// URI paramaters, map[string]string
	params := wctx.Params()
	// route, the webgo.Route which is executing this request
	route := wctx.Route
	webgo.R200(
		w,
		fmt.Sprintf(
			"Route name: '%s', params: '%s'",
			route.Name,
			params,
		),
	)
}

Handler chaining

Handler chaining lets you execute multiple handlers for a given route. Execution of a chain can be configured to run even after a handler has written a response to the HTTP request, if you set FallThroughPostResponse to true (refer sample).

Middleware

WebGo middlware lets you wrap all the routes with a middleware unlike handler chaining. The router exposes a method Use && UseOnSpecialHandlers to add a Middleware to the router.

NotFound && NotImplemented are considered Special handlers. webgo.Context(r) within special handlers will return nil.

Any number of middleware can be added to the router, the order of execution of middleware would be LIFO (Last In First Out). i.e. in case of the following code

func main() {
	router.Use(accesslog.AccessLog, cors.CORS(nil))
	router.Use(<more middleware>)
}

CorsWrap would be executed first, followed by AccessLog.

Error handling

Webgo context has 2 methods to set & get erro within a request context. It enables Webgo to implement a single middleware where you can handle error returned within an HTTP handler. set error, get error.

Helper functions

WebGo provides a few helper functions. When using Send or SendResponse (other Rxxx responder functions), the response is wrapped in WebGo's response struct and is serialized as JSON.

{
  "data": "<any valid JSON payload>",
  "status": "<HTTP status code, of type integer>"
}

When using SendError, the response is wrapped in WebGo's error response struct and is serialzied as JSON.

{
  "errors": "<any valid JSON payload>",
  "status": "<HTTP status code, of type integer>"
}

HTTPS ready

HTTPS server can be started easily, by providing the key & cert file. You can also have both HTTP & HTTPS servers running side by side.

Start HTTPS server

cfg := &webgo.Config{
	Port: "80",
	HTTPSPort: "443",
	CertFile: "/path/to/certfile",
	KeyFile: "/path/to/keyfile",
}
router := webgo.NewRouter(cfg, routes()...)
router.StartHTTPS()

Starting both HTTP & HTTPS server

cfg := &webgo.Config{
	Port: "80",
	HTTPSPort: "443",
	CertFile: "/path/to/certfile",
	KeyFile: "/path/to/keyfile",
}

router := webgo.NewRouter(cfg, routes()...)
go router.StartHTTPS()
router.Start()

Graceful shutdown

Graceful shutdown lets you shutdown the server without affecting any live connections/clients connected to the server. Any new connection request after initiating a shutdown would be ignored.

Sample code to show how to use shutdown

func main() {
	osSig := make(chan os.Signal, 5)

	cfg := &webgo.Config{
		Host:            "",
		Port:            "8080",
		ReadTimeout:     15 * time.Second,
		WriteTimeout:    60 * time.Second,
		ShutdownTimeout: 15 * time.Second,
	}
	router := webgo.NewRouter(cfg, routes()...)

	go func() {
		<-osSig
		// Initiate HTTP server shutdown
		err := router.Shutdown()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		} else {
			fmt.Println("shutdown complete")
			os.Exit(0)
		}

		// If you have HTTPS server running, you can use the following code
		// err := router.ShutdownHTTPS()
		// if err != nil {
		// 	fmt.Println(err)
		// 	os.Exit(1)
		// } else {
		// 	fmt.Println("shutdown complete")
		// 	os.Exit(0)
		// }
	}()

	go func(){
		time.Sleep(time.Second*15)
		signal.Notify(osSig, os.Interrupt, syscall.SIGTERM)
	}()

	router.Start()
}

Logging

WebGo exposes a singleton & global scoped logger variable LOGHANDLER with which you can plug in your custom logger by implementing the Logger interface.

Configuring the default Logger

The default logger uses Go standard library's log.Logger with os.Stdout (for debug and info logs) & os.Stderr (for warning, error, fatal) as default io.Writers. You can set the io.Writer as well as disable specific types of logs using the GlobalLoggerConfig(stdout, stderr, cfgs...) function.

Server-Sent Events

MDN has a very good documentation of what SSE (Server-Sent Events) are. The sample app provided shows how to use the SSE extension of webgo.

Usage

A fully functional sample is provided here.

Benchmark

  1. the-benchmarker
  2. go-web-framework-benchmark

Contributing

Refer here to find out details about making a contribution

Credits

Thanks to all the contributors

The gopher

The gopher used here was created using Gopherize.me. WebGo stays out of developers' way, so sitback and enjoy a cup of coffee.

webgo's People

Contributors

bnkamalesh avatar hlts2 avatar kirilldanshin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webgo's Issues

spelling error

Hello,

Thanks for developing this simple framework.
As a non-voice developer I can easily lift up with your framework.
file word written as fil in errors.go file.

//C003 Error Code 3
C003 = "App environment provided in config fil Accepted values are production or development"

-Vasu

url with trailing slash /matchall/webgo/ and /matchall/webgo/ all return 200 not 404

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. git clone https://github.com/bnkamalesh/webgo/blob/master/cmd/main.go
  2. go run main
  3. curl http://localhost:8080/matchall/
    curl http://localhost:8080/matchall/webgo/
  4. "status":200

Expected behavior
A clear and concise description of what you expected to happen.

curl http://localhost:8080/matchall/ return 404
curl http://localhost:8080/matchall/xxx/ return 404
like net/http

package main
import (
    "fmt"
    "net/http"
)
func main() {
    http.HandleFunc("/matchall/webgo", func (w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Welcome to my website!")
    })
   http.ListenAndServe(":80", nil)
}

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS:win7
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Plugging database

Hello, I'm wondering how can I plug sqlx in order to use MySQL database. A sample code would be very appreciated.

Route grouping

Is your feature request related to a problem? Please describe.

If you want to group a set of APIs under a particular prefix (e.g. all URIs starting with /v2), it's tedious or have to verify manually at multiple places.

Describe the solution you'd like

Create a Route group capability where we append to the current list of routes. e.g.

v2Routes := webgo.NewGroup("/v2", <skipRouterMiddleware>, routes...)
v2Routes.Add(*Route...)

// skipRouterMiddleware is a boolean, which if set to true, all middleware applied using router.Use will be skipped from this route group

Each URI should be automatically be prefixed with the group prefix. In the above example, the group prefix is /v2. After adding the prefix, the URI would look like /v2/<URI>

Describe alternatives you've considered

The same can be easily achieved outside of webgo's scope. Since it is merely maintaining a list of *Route. Though all the methods and implementation adds to the convenience of developers

Additional context
N/A

Auto HTTPS with Letsencrypt

If autoTLS is enabled, it should do the following:

  • Check if there's a certificate path provided, if not, default to a path
  • Inject acme routes for Letsencrypt verification
  • Accept list of domains to provide HTTPS
  • Check expiry of all generated Letsencrypt certificates
  • Update certificates automatically N days prior to expiry

Invalid response HTTP status

file: responses.go

When responses are send using SendResponse or SendError, in case of a JSON encoding error within these functions, the following happens:

w.WriteHeader(rCode) // Write header is already called here, this cannot be overwritten if err := json.NewEncoder(w).Encode(&dOutput{data, rCode}); err != nil { Log.Println(err) R500(w, ErrInternalServer) // HTTP response status set by this function will not work }

So the response in such cases would look like this:
HTTP Status: 200 { errors: "Internal server error occurred", status: 500 }

About fasthttp support

The project was installed on the net/http package as the base. In addition, we can bring fasthttp support. I can even develop it. :)

Convenience methods for adding routes

Is your feature request related to a problem? Please describe.

Adding routes currently requires the developer to prepare a single list of *Route with all the routes defined in one go. This can be split up and made easier for the developer

Describe the solution you'd like

We can add convenience method for each type of HTTP method supported by webgo (). e.g.

router.Add(*Route)
router.Get("URI",[]Handlers{}, opts...)
router.Head("URI",[]Handlers{}, opts...)
router.Post("URI",[]Handlers{}, opts...)
router.Put("URI",[]Handlers{}, opts...)
router.Patch("URI",[]Handlers{}, opts...)
router.Delete("URI",[]Handlers{}, opts...)
router.Option("URI",[]Handlers{},opts...)

Each method should keep updating routes of the router, for the respective HTTP method.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

feat: HTTP cache implementation.

Is your feature request related to a problem? Please describe.
An HTTP cache system would be great in webgo to avoid the execution of unchanged response.

Describe the solution you'd like
I can implement Souin as the HTTP cache middleware. With that it will support the CDN validation/invalidation too, set default cache-control header, store in a distributed system using olric or in memory with badger.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
It's already available as Træfik/Tyk plugin, skipper/gin/echo middleware, and is used in the official caddy cache-handler.

Cheers ✌️

Add provision of setting and getting Error

Since all the handlers are std lib compliant, it's difficult to do a centralized/easy of error logging. Hence, implementing Webgotcontext.SetErrror(err error) & Webgocontext.Error() error would be useful. And we could write a normal middleware which fetches the the error from webgocontext and handle appropriately

Support to choose the logging interface

By default the logs are printed to stdout. Though, there should be a provision of providing an output of users' choice. Need to update the logging mechanism to use an interface, so that it can be set to a thirdparty/external logger

  • Convert current logs to use an interface
  • Expose a method to replace the logging interface on the fly (should be concurrency safe)

Comparison benchmark

Comparison benchmark done between multiple frameworks, in an identical environment and the exact same functionality.

optional parameters

Is your feature request related to a problem? Please describe.
Unable to use optional parameters

Describe the solution you'd like
To have the ability to use optional parameters that would allow the use of /user or /user/1

Additional context

// something like
Pattern: "/user/:id?"

Route example in readme gives error: errors.go:54: Unsupported HTTP request method provided.

Hello. This code in the readme:

import (
	"github.com/bnkamalesh/webgo"
	"github.com/bnkamalesh/webgo/middleware"
)

func routes() []*webgo.Route {
	return []*webgo.Route{
		&webo.Route{
			Name: "home",
			Pattern: "/",
			Handlers: []http.HandlerFunc{
				func(w http.ResponseWriter, r *http.Request) {
					webgo.R200(w, "home")
				}
			},
		},
	}
}

func main() {
	router := webgo.NewRouter(*webgo.Config, routes())

	router.UseOnSpecialHandlers(middleware.AccessLog)
	
	router.Use(middleware.AccessLog)

	router.Start()
}

Doesn't work. You need to define a Method field in the Route struct. Also it complains about *webgo.Config not being an expression (unless it was intentional as a placeholder for any pointer to Config). This works:

func routes() []*webgo.Route {
	return []*webgo.Route{
		&webo.Route{
			Name: "home",
			Method: "GET",	
			Pattern: "/",
			Handlers: []http.HandlerFunc{
				func(w http.ResponseWriter, r *http.Request) {
					webgo.R200(w, "home")
				}
			},
		},
	}
}

func main() {
	config := webgo.Config{
		Host: "localhost",
		Port: "8888",
	}
	router := webgo.NewRouter(&config, routes())

	router.UseOnSpecialHandlers(middleware.AccessLog)
	
	router.Use(middleware.AccessLog)

	router.Start()
}

Login Auth solutions.

Is your feature request related to a problem? Please describe.
I wanted to get some examples of how to add login authentication. I have some ideas myself, but curious what the world has in mind.

Describe the solution you'd like
I would like to see examples for:
Firebase auth
3rd party Auth
perhaps some JWT and or cookie solutions

CORS middleware update

CORS middleware provided with the package currently responds with a wildcard *. It should be updated to accept a list of domains, and default to wildcard if no domains provided.

  • All CORS middleware functions should accept an optional list of domains
  • Do not break backward compatibility / New functions if cannot maitnain backward compatibility

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.