router

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Dec 2, 2024 License: MIT, MIT Imports: 13 Imported by: 0

README

router

router is a Go library that provides an HTTP/2-enabled router with CORS support and a customizable 404 handler. The package leverages the Gin framework internally to handle routing and middleware. However, Gin is not exposed externally, which allows for the easy replacement of the underlying framework in the future without affecting the external API of the package.

Features

  • HTTP/2 Support
    • The router comes with HTTP/2 support out of the box, using the h2c package to provide cleartext HTTP/2 handling.
  • CORS Support
    • CORS policies are configurable via the Config struct, allowing control over origins, headers, methods, and credentials.
  • Graceful Shutdown
    • The router listens to context cancellation signals to shut down gracefully, ensuring ongoing connections are closed properly.
  • Custom 404 Handler
    • You can define a custom handler for undefined routes, allowing more control over the application's behavior when a route is not found.

Installation

go get github.com/albeebe/service/pkg/router

Usage

Create a New Router

To create and configure a new router, use the NewRouter function. It requires a context.Context for managing the lifecycle and a Config struct for customization.

ctx := context.Background()

config := Config{
    Host: "localhost:8080",
    Cors: &Cors{
        AllowOrigins: []string{"*"},
        AllowMethods: []string{"GET", "POST"},
    },
}

router, err := NewRouter(ctx, config)
if err != nil {
    log.Fatalf("failed to create router: %v", err)
}
Register Routes

You can register route handlers using the RegisterHandler function, which takes an HTTP method, path, and handler function. The handler function is a standard http.HandlerFunc.

router.RegisterHandler("GET", "/ping", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("pong"))
})
Start the Server

To start the server, call the ListenAndServe method. This will start the server in a separate goroutine and return a channel for capturing any errors.

errChan := router.ListenAndServe()

// Capture any errors
if err := <-errChan; err != nil {
    log.Fatalf("server error: %v", err)
}
Send HTTP Responses

You can use the SendResponse helper function to send responses to clients, including setting headers and streaming the body.

headers := http.Header{
    "Content-Type": []string{"application/json"},
}
body := io.NopCloser(strings.NewReader(`{"message": "Hello, World!"}`))

SendResponse(w, http.StatusOK, headers, body)
Graceful Shutdown

The router listens for context cancellation to shut down the server gracefully. This happens automatically when the context passed to NewRouter is canceled.

To explicitly shut down the router, you can call:

router.Shutdown()

Internals

This package uses the Gin framework internally for routing and middleware but does not expose Gin-specific functionality directly. This abstraction allows flexibility for future changes, such as swapping Gin for another framework, without affecting the router's public API.

Example

package main

import (
	"context"
	"encoding/json"
	"log"
	"net/http"
	"github.com/albeebe/service/pkg/router"
)

func main() {
    ctx := context.Background()
    
    // Define a custom NoRouteHandler
    noRouteHandler := func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "text/plain")
        w.WriteHeader(http.StatusNotFound)
        w.Write([]byte("not found"))
    }
    
    // Create the config with the custom NoRouteHandler
    config := router.Config{
        Host: "localhost:8080",
        Cors: &router.Cors{
            AllowOrigins: []string{"*"},
            AllowMethods: []string{"GET", "POST"},
        },
        NoRouteHandler: &noRouteHandler,
    }
    
    // Initialize the router
    r, err := router.NewRouter(ctx, config)
    if err != nil {
        log.Fatalf("failed to create router: %v", err)
    }
    
    // Register some example routes
    r.RegisterHandler("GET", "/ping", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("pong"))
    })
    
    // Start the server
    errChan := r.ListenAndServe()
    
    log.Printf("Server running at %s", config.Host)
    
    // Capture any server errors
    if err := <-errChan; err != nil {
        log.Fatalf("server error: %v", err)
    }
}

License

This project is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Feel free to open an issue or submit a pull request with any proposed changes.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SendResponse

func SendResponse(w http.ResponseWriter, statusCode int, headers http.Header, body io.ReadCloser) error

SendResponse sends an HTTP response with the provided status code, headers, and body content to the client. It streams the body data in chunks, ensures headers are set correctly, and handles client disconnection or errors during streaming.

Types

type Config

type Config struct {
	Host           string                                        // Server host address
	Cors           *Cors                                         // CORS configuration
	NoRouteHandler *func(w http.ResponseWriter, r *http.Request) // Custom handler for undefined routes
}

Config holds the server configuration options, including the host address, CORS settings, and a custom handler for undefined routes.

func (*Config) Validate

func (c *Config) Validate() error

validate checks the Config struct for required fields and returns an error if any required fields are missing

type Cors

type Cors struct {
	// AllowOrigins is a list of origins that are allowed to access the server's resources.
	// You can use "*" as a wildcard to allow all origins.
	// Example: ["https://example.com", "https://another-site.com"] or ["*"] to allow all.
	AllowOrigins []string

	// AllowMethods is a list of HTTP methods that are allowed for cross-origin requests.
	// You can use "*" as a wildcard to allow all methods.
	// Example: ["GET", "POST", "PUT"] or ["*"] to allow all methods.
	AllowMethods []string

	// AllowHeaders is a list of headers that the server allows in cross-origin requests.
	// You can use "*" as a wildcard to allow all headers.
	// Example: ["Content-Type", "Authorization", "X-Custom-Header"] or ["*"] to allow all headers.
	AllowHeaders []string

	// ExposeHeaders is a list of headers that the browser is allowed to access in the response
	// from the server during a CORS request. You can use "*" as a wildcard to allow access to all headers.
	// Example: ["X-Response-Time", "Content-Length"] or ["*"] to expose all headers.
	ExposeHeaders []string

	// AllowCredentials indicates whether credentials (like cookies, HTTP authentication, etc.)
	// are allowed in cross-origin requests. Note: If AllowOrigins is set to "*", this must be false
	// as credentials cannot be used with a wildcard origin.
	// Example: true to allow credentials to be sent with the request, false otherwise.
	AllowCredentials bool

	// MaxAge is the duration for which the results of a preflight request (OPTIONS) can be cached
	// by the browser.
	// Example: time.Hour()
	MaxAge time.Duration
}

Cors defines the structure for configuring Cross-Origin Resource Sharing (CORS) settings. These settings control how a server responds to requests from different origins, specifying what is allowed in terms of origins, methods, headers, etc. For fields like AllowOrigins, AllowMethods, and AllowHeaders, setting the value to "*" will allow any value (e.g., any origin, any method, or any header).

type Router

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

Router wraps the HTTP server, managing routing and lifecycle (graceful shutdown).

func NewRouter

func NewRouter(ctx context.Context, config Config) (*Router, error)

NewRouter creates and configures a new Router with HTTP/2, CORS support, and a custom 404 handler. It validates the provided config and listens for a context cancellation to gracefully shut down.

func (*Router) ListenAndServe

func (r *Router) ListenAndServe() chan error

ListenAndServe starts the HTTP server in a separate goroutine and returns a channel that captures any errors.

func (*Router) RegisterHandler

func (r *Router) RegisterHandler(method, relativePath string, handler func(w http.ResponseWriter, r *http.Request)) error

RegisterHandler registers a handler for the specified HTTP method and path.

func (*Router) Shutdown

func (r *Router) Shutdown() error

Shutdown gracefully shuts down the server, waiting for ongoing connections to finish.

Jump to

Keyboard shortcuts

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