goster

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Mar 18, 2025 License: MIT Imports: 19 Imported by: 0

README

Goster 🚀

GoDoc Go Report Card License Go version

Welcome to Goster, a lightweight and efficient web framework for Go. Goster provides a minimal abstraction over Go’s built-in net/http package, allowing you to rapidly build microservices and APIs with little overhead. Its design emphasizes simplicity and performance, offering an intuitive API for routing, middleware, and more. 🌟

Why Goster?

  • 🚀 Fast and Lightweight: Built with simplicity in mind, Goster adds only a thin layer on top of Go’s net/http, ensuring minimal performance overhead. Hello-world benchmarks show Goster’s throughput to be on par with the Go standard library and top Go frameworks (Gin handles ~100k req/s on similar hardware (Fiber vs Gin: A Comparative Analysis for Golang - tillitsdone.com), and Goster achieves comparable results).
  • 📊 Intuitive API: Goster’s API is easy to learn and use, simplifying web development without sacrificing flexibility. Define routes with clear semantics and handle requests with a simple context object.
  • 🛠 Extensible Middleware: Add middleware functions globally or for specific routes to enhance functionality. This makes it easy to implement logging, authentication, or other cross-cutting concerns.
  • 🔍 Dynamic Routing: Effortlessly handle paths with parameters (e.g. /users/:id). Goster automatically parses URL parameters for you.
  • 🗂️ Static Files & Templates: Serve static assets (CSS, JS, images, etc.) directly from a directory, and render HTML templates with ease.
  • 🧪 Logging: Built-in logging captures all incoming requests and application messages. Goster stores logs internally for inspection and can print to stdout with different levels (Info, Warning, Error).

Installation

Install Goster using Go modules. Run the following command in your project:

go get -u github.com/dpouris/goster

This will add Goster to your Go module dependencies. Goster requires Go 1.18+ (Go 1.21 is recommended, as indicated in the module file).

Quick Start

Get your first Goster server running in just a few lines of code:

package main

import "github.com/dpouris/goster"

func main() {
    g := goster.NewServer()

    g.Get("/", func(ctx *goster.Ctx) error {
        ctx.Text("Hello, Goster!")
        return nil
    })

    // Use the new Start function instead of ListenAndServe
    g.Start(":8080")
}

You can also start a secure server with TLS:

package main

import "github.com/dpouris/goster"

func main() {
    g := goster.NewServer()
    
    // Replace with actual certificate and key paths
    g.StartTLS(":8443", "path/to/cert.pem", "path/to/key.pem")
}

Run the server: Build and run your Go program, then navigate to http://localhost:8080. You should see “Hello, Goster!” in your browser, served by your new Goster server.

This example creates a basic HTTP server that listens on port 8080 and responds with a text message for the root URL. For a more detailed tutorial, see the Getting Started guide.

Usage Examples

Goster’s API lets you set up routes and middleware in a straightforward way. Below are some common usage patterns. For comprehensive documentation, refer to the docs/ directory.

  • Defining Routes: Use methods like Get, Post, Put, etc., on your server to register routes. For example:

    g.Get("/hello", func(ctx *goster.Ctx) error {
        return ctx.Text("Hello World")
    })
    

    This registers a handler for GET /hello. You can similarly use g.Post, g.Put, g.Patch, g.Delete, etc., to handle other HTTP methods.

  • Dynamic URL Parameters: Define routes with parameters using the : prefix. For instance:

    g.Get("/users/:id", func(ctx *goster.Ctx) error {
        userID, _ := ctx.Path.Get("id")  // retrieve the :id parameter
        return ctx.Text("Requested user " + userID)
    })
    

    Goster will capture the segment after /users/ as an id parameter. In the handler, ctx.Path.Get("id") provides the value. (See Routing for more on dynamic routes.)

  • Query Parameters: Access query string values via ctx.Query. For example, for a URL like /search?q=term:

    g.Get("/search", func(ctx *goster.Ctx) error {
        q, exists := ctx.Query.Get("q")
        if exists {
            return ctx.Text("Search query is: " + q)
        }
        return ctx.Text("No query provided")
    })
    

    Here ctx.Query.Get("q") checks if the q parameter was provided and returns its value. (See Context and Responses for details.)

  • Middleware: You can attach middleware functions that run before your route handlers. Use UseGlobal for middleware that should run on all routes, or Use(path, ...) for middleware on specific routes. For example:

    // Global middleware (runs for every request)
    g.UseGlobal(func(ctx *goster.Ctx) error {
        // e.g., start time tracking or authentication check
        return nil
    })
    
    // Path-specific middleware (runs only for /admin routes)
    g.Use("/admin", func(ctx *goster.Ctx) error {
        // e.g., verify admin privileges
        return nil
    })
    

    (See the Middleware documentation for more examples and use cases.)

  • Serving Static Files: Goster can serve static files (like images, CSS, JS) from a directory. Use g.StaticDir("<dir>") to register a static files directory. For example, g.StaticDir("static") will serve files in the static/ folder at URLs matching the file paths. If you have static/logo.png, it becomes accessible at http://localhost:8080/static/logo.png. (See Static Files for setup and details.)

  • HTML Templates: To serve HTML pages, place your template files (e.g. .gohtml or .html) in a directory and register it with g.TemplateDir("<dir>"). Then use ctx.Template("<file>", data) in a handler to render the template. For example:

    g.TemplateDir("templates")
    
    g.Get("/hello/:name", func(ctx *goster.Ctx) error {
        name, _ := ctx.Path.Get("name")
        return ctx.Template("hello.gohtml", name)
    })
    

    This will load templates/hello.gohtml, execute it (optionally with name data passed), and send the result as the response. (See Templates for template guidelines.)

  • JSON Responses: Goster provides a convenient ctx.JSON(obj) method to respond with JSON. Simply pass any Go value (struct, map, etc.), and Goster will serialize it to JSON and set the appropriate content type. For example:

    g.Get("/status", func(ctx *goster.Ctx) error {
        data := map[string]string{"status": "ok"}
        return ctx.JSON(data)
    })
    

    The client will receive a JSON object: {"status":"ok"}. (See Context and Responses for details on JSON serialization.)

  • Logging: Every Goster server has an embedded logger. You can use it to log custom events:

    goster.LogInfo("Server started", g.Logger)
    goster.LogWarning("Deprecated endpoint called", g.Logger)
    goster.LogError("An error occurred", g.Logger)
    

    These will print timestamped log entries to standard output. Goster also keeps an in-memory log of all requests and log messages. You can access g.Logs (a slice of log strings) for debugging or expose it via an endpoint. For instance, you might add a route to dump logs for inspection. (See Logging for more.)

The above examples only scratch the surface. Check out the docs/ directory for detailed documentation of each feature, and refer to the examples/ directory in the repository for ready-to-run example programs.

Documentation

You can find full documentation for Goster in the docs/ directory of the repository. The documentation includes guides and reference for all major features:

  • Getting Started – High-level guide to building a simple service with Goster.
  • Routing – Defining routes, path parameters, and handling requests.
  • Middleware – Using global and route-specific middleware for advanced functionality.
  • Static Files – Serving static content (assets) through Goster.
  • Templates – Configuring template directories and rendering HTML views.
  • Context and Responses – How the request context works, and responding with text/JSON.
  • Logging – Utilizing Goster’s logging capabilities for your application.

Feel free to explore the docs. Each section contains examples and best practices. If something isn’t clear, check the examples provided or raise an issue — we’re here to help!

Benchmarks

Performance is a key focus of Goster. We ran benchmarks comparing Goster to other Go web frameworks and the native net/http package:

  • Hello World throughput: In a simple "Hello World" HTTP benchmark, Goster achieved throughput comparable to using net/http directly, demonstrating negligible overhead. For example, popular Go frameworks like Gin (which also builds on net/http) handle on the order of 100k requests per second on standard hardware (Fiber vs Gin: A Comparative Analysis for Golang - tillitsdone.com). Goster’s performance is in the same ballpark, thanks to its minimalistic design (essentially just a light routing layer on top of the standard library).

  • Routing overhead: Goster uses simple map lookups for routing, so route matching is fast even with dynamic parameters. In our tests, adding URL parameters had no significant impact on request latency. The latency remained in the microsecond range (per request) for routing logic, similar to other lightweight routers.

  • Comparison with fasthttp frameworks: Frameworks like Fiber use the fasthttp engine for even higher throughput. Fiber can edge out Gin by roughly 10-20% in some benchmarks (Fiber vs Gin: A Comparative Analysis for Golang - tillitsdone.com). Goster, using Go’s standard HTTP server, is slightly below Fiber’s extreme throughput but still sufficiently fast for the vast majority of use cases. It delivers performance close to Go’s raw HTTP capabilities.

Conclusion: You can expect Goster to perform on par with other minimal Go web frameworks. It’s suitable for high-throughput scenarios, and you likely won’t need to micro-optimize beyond what Goster provides out-of-the-box. (If you have specific performance requirements, we welcome community benchmarks and feedback!)

Comparison with Similar Libraries

Goster is part of a rich ecosystem of Go web frameworks. Here’s how it compares to a few popular choices:

  • Go net/http: The standard library provides the low-level HTTP server and mux. Goster uses net/http under the hood, so it feels familiar but saves you from writing repetitive boilerplate. Unlike using net/http alone, Goster handles common tasks (routing, parameters, etc.) for you. If you need absolute minimal dependency and are comfortable implementing everything from scratch, net/http is always an option – but Goster gives you the same performance with more convenience.

  • Gorilla Mux: Gorilla Mux was a widely-used router for Go. It offered powerful routing (with URL variables, regex, etc.), but the project is now archived (“discontinued”) (Goster Alternatives and Reviews). Goster provides similar routing capabilities (dynamic paths with variables) with a simpler API. If you’re looking for a replacement for Gorilla Mux, Goster’s routing can feel familiar, though it intentionally omits some of Gorilla’s more complex features to remain lightweight.

  • Chi: Chi is another minimal router for Go that focuses on idiomatic use of context.Context. Chi and Goster have similar philosophies – both aim to be lightweight and idiomatic. Chi has a rich ecosystem of middlewares and is a mature project. Goster differentiates itself by bundling a few extra conveniences (like built-in logging and static file serving) out-of-the-box, whereas Chi often relies on add-ons for such features.

  • Gin: Gin is a powerful framework with an API similar to Goster’s (context-based, routing with parameters, middleware support). Gin uses a radix tree for routing and is highly optimized. It’s a proven framework with a large community and many plugins. Goster, by contrast, is more minimal and young. If you need features like validation, serialization, or a large ecosystem of middleware, Gin might be a better choice. However, if you prefer something simpler than Gin with only the essentials, Goster is a good fit. Performance-wise, Goster and Gin are both very fast (both build on net/http), with Gin possibly having a slight edge in some routing scenarios due to its internal optimizations.

  • Fiber: Fiber is a framework built on top of the fasthttp library (bypassing net/http for performance). It has an API inspired by Express.js. Fiber can offer higher throughput in certain benchmarks (Fiber vs Gin: A Comparative Analysis for Golang - tillitsdone.com), but using a custom HTTP engine means it’s less compatible with some net/http middleware and requires careful handling of certain aspects (like streaming, HTTP/2 support, etc.). Goster sticks to the standard net/http for maximum compatibility and simplicity. If you need extreme performance and are willing to trade some compatibility, Fiber is an alternative; otherwise, Goster’s performance is usually more than sufficient.

In summary, Goster’s niche is for developers who want a very light, idiomatic Go web framework. It may not (yet) have all the bells and whistles of Gin or the ultra-performance of Fiber, but it covers the common needs for building APIs and microservices with minimal fuss. As the project grows, we aim to maintain this balance of simplicity and capability.

FAQs

Q1: What Go version do I need to use Goster?
A: Go 1.18 or later is required. Goster is tested with the latest Go versions (the module file indicates Go 1.21). Using an up-to-date Go release is recommended to ensure compatibility with the any type and other modern Go features used by Goster.

Q2: How do I define routes with URL parameters (dynamic routes)?
A: Simply include parameters in the path prefixed with :. For example, /users/:id/profile defines a route with an id parameter. In your handler, use ctx.Path.Get("id") to retrieve the value. See the Routing documentation for details and examples.

Q3: Can Goster handle query string parameters?
A: Yes. Use ctx.Query.Get("<name>") to retrieve query parameters. This returns the value and a boolean indicating if it was present. For instance, for /search?q=test, ctx.Query.Get("q") would return "test". If a parameter is missing, the returned boolean will be false (and the value empty).

Q4: How do I return JSON responses?
A: Use the ctx.JSON(data interface{}) method. Pass any Go data (e.g. a struct or map), and Goster will serialize it to JSON and send it with Content-Type: application/json. Under the hood it uses Go’s encoding/json. Example: ctx.JSON(map[string]string{"status": "ok"}) will return {"status":"ok"} to the client. (See Context and Responses for more.)

Q5: How can I serve static files (CSS, JavaScript, images)?
A: Call g.StaticDir(<directory>) on your server. Suppose you have a folder assets/ with static files – use g.StaticDir("assets"). All files in that directory will be served at paths prefixed with the directory name. For example, assets/main.js can be fetched from http://yourserver/assets/main.js. Goster will automatically serve the file with the correct content type. (See Static Files docs for configuration tips.)

Q6: Does Goster support HTTPS (TLS)?
A: Goster itself doesn’t include a TLS server implementation, but you can use Go’s standard methods to run HTTPS. For example, you can call http.ListenAndServeTLS(port, certFile, keyFile, g), passing your Goster server (g) as the handler. Since Goster’s ListenAndServe is a thin wrapper, using net/http directly for TLS is straightforward. Alternatively, you can put Goster behind a reverse proxy (like Nginx or Caddy) for TLS termination.

Q7: Can I use Goster’s middleware with standard net/http handlers or integrate external middleware?
A: Goster is compatible with the net/http ecosystem. You can wrap Goster’s goster.Ctx inside a standard http.Handler if needed, or use g.Router (or similar) to mount external handlers. Conversely, you can use g.Use() to add middleware that interacts with ctx.Request and ctx.Response which are standard *http.Request and http.ResponseWriter under the hood. Many external middlewares (for logging, tracing, etc.) can be adapted to Goster by accessing ctx.Request/ctx.Response. It may require a bit of glue code, but it’s doable thanks to Goster’s design around the standard library.

Q8: How do I render HTML templates with dynamic data?
A: First, set the templates directory with g.TemplateDir("templates") (replace "templates" with your folder name). Then, in a handler use ctx.Template("file.gohtml", data). Ensure your template file (e.g. file.gohtml) is in the templates directory. The data can be any Go value or struct that your template expects. Goster will execute the template and write the output. (See Templates for an example). If you see an error or nothing renders, make sure your template name and data are correct and that you called TemplateDir during setup.

Q9: Is Goster ready for production use?
A: Goster is MIT-licensed and open source. It is a young project (still below 1.0 version), but its core functionality is tested and quite stable. It’s suitable for small to medium projects and learning purposes. As of now, it might not have as large a community or ecosystem as more established frameworks. We recommend evaluating it against your requirements. For many microservices, Goster should work well. As always, you should conduct your own testing (including concurrency and load testing) to ensure it meets your production needs. We are actively improving Goster, and welcome issues or contributions to help make it production-ready for a wider range of use cases.

Q10: How can I contribute or report an issue?
A: Contributions are welcome! If you find a bug or have an idea for improvement, please open an issue on GitHub. If you’d like to contribute code, you can fork the repository and open a pull request. For major changes, it’s best to discuss via an issue first. Be sure to follow the existing code style and include tests for new features or fixes. See the Contributing Guide for more details on the contribution process and project standards.

Contribution Guidelines

I warmly welcome contributions from the community. Whether it’s bug fixes, new features, or improvements to documentation, your help is appreciated. To contribute:

  • Report Issues: If you encounter a bug or have a question/idea, open an issue on GitHub. Please provide details and steps to reproduce for bugs. For feature requests, describe the use case and potential solutions.
  • Submit Pull Requests: Fork the repository and create a branch for your changes. Try to follow the code style of the project and include tests for any new code. Once you’re ready, open a pull request with a clear description of your changes. The project maintainer will review your contribution.
  • Join Discussions: You can also participate in discussions by commenting on issues or proposing design suggestions. Input from users helps shape the project’s direction.
  • Development Setup: To work on Goster, clone the repo and run go mod tidy to install dependencies. Run go test ./... to ensure all tests pass. You can use the example programs under examples/ for manual testing. There's also a folder called utilities/ that contains QoL scripts that may come useful during development.

For more detailed guidelines, please refer to the CONTRIBUTING.md file in the repository.

License

Goster is open source and available under the MIT License. This means you are free to use, modify, and distribute it in your own projects. See the LICENSE file for the full license text.

Happy coding with Goster! 🚀

Documentation

Index

Constants

View Source
const (
	TypeStatic   = "static"
	TypeDynamic  = "dynamic"
	TypeWildcard = "wildcard"
)

Variables

This section is empty.

Functions

func DefaultHeader

func DefaultHeader(c *Ctx)

Adds basic headers

func LogError

func LogError(msg string, logger *log.Logger)

Supply msg with a string value to be logged to the console and a logger

func LogInfo

func LogInfo(msg string, logger *log.Logger)

Supply msg with a string value to be logged to the console and a logger

func LogWarning

func LogWarning(msg string, logger *log.Logger)

Supply msg with a string value to be logged to the console and a logger

Types

type Config

type Config struct {
	BaseTemplateDir string
	StaticDir       string
	TemplatePaths   map[string]string
	StaticFilePaths map[string]string
}

func (*Config) AddStaticFilePath

func (c *Config) AddStaticFilePath(relPath string, fullPath string) (added bool)

func (*Config) AddTemplatePath

func (c *Config) AddTemplatePath(relPath string, fullPath string) (added bool)

type Ctx

type Ctx struct {
	Request  *http.Request
	Response Response
	Meta
}

func NewContext added in v0.2.0

func NewContext(r *http.Request, w http.ResponseWriter) Ctx

func NewContextCreation added in v0.2.0

func NewContextCreation(url string) Ctx

func (*Ctx) HTML

func (c *Ctx) HTML(t string) (err error)

Send an HTML f file to the client. If if file not in FilesDir dir then will return error.

func (*Ctx) JSON

func (c *Ctx) JSON(j any) (err error)

Send back a JSON response. Supply j with a value that's valid marsallable(?) to JSON -> error

func (*Ctx) Redirect added in v0.2.0

func (c *Ctx) Redirect(url string, code int)

func (*Ctx) Template

func (c *Ctx) Template(t string, data any) (err error)

Send an HTML template t file to the client. If template not in template dir then will return error.

func (*Ctx) TemplateWithFuncs added in v0.2.0

func (c *Ctx) TemplateWithFuncs(t string, data any, funcMap template.FuncMap) (err error)

Send an HTML template t file to the client. TemplateWithFuncs supports functions to be embedded in the html template for use. If template not in template dir then will return error.

func (*Ctx) Text

func (c *Ctx) Text(s string)

Send plain text to the client

type Engine

type Engine struct {
	Goster *Goster

	Config *Config
	// contains filtered or unexported fields
}

func (*Engine) DefaultConfig

func (e *Engine) DefaultConfig()

Set the default config settings for the engine

func (*Engine) SetStaticDir

func (e *Engine) SetStaticDir(path string) (err error)

func (*Engine) SetTemplateDir

func (e *Engine) SetTemplateDir(path string) (err error)

Sets the template directory to `d` relative to the path of the executable.

type Goster

type Goster struct {
	Routes     Routes                      // Routes is a map of HTTP methods to their respective route handlers.
	Middleware map[string][]RequestHandler // Middleware is a map of routes to their respective middleware handlers.
	Logger     *log.Logger                 // Logger is used for logging information and errors.
	Logs       []string                    // Logs stores logs for future reference.
}

Goster is the main structure of the package. It handles the addition of new routes and middleware, and manages logging.

func NewServer

func NewServer() *Goster

NewServer creates a new Goster instance.

func (*Goster) Delete

func (g *Goster) Delete(path string, handler RequestHandler) error

Delete creates a new Route under the DELETE method for `path`. If the Route aleady exists an error is returned.

func (*Goster) Get

func (g *Goster) Get(url string, handler RequestHandler) error

Get creates a new Route under the GET method for `path`. If the Route aleady exists an error is returned.

func (*Goster) Patch

func (g *Goster) Patch(path string, handler RequestHandler) error

Patch creates a new Route under the PATCH method for `path`. If the Route aleady exists an error is returned.

func (*Goster) Post

func (g *Goster) Post(path string, handler RequestHandler) error

Post creates a new Route under the POST method for `path`. If the Route aleady exists an error is returned.

func (*Goster) Put

func (g *Goster) Put(path string, handler RequestHandler) error

Put creates a new Route under the PUT method for `path`. If the Route aleady exists an error is returned.

func (*Goster) ServeHTTP

func (g *Goster) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP is the handler for incoming HTTP requests to the server. It parses the request, manages routing, and is required to implement the http.Handler interface.

func (*Goster) Start added in v0.2.0

func (g *Goster) Start(p string)

Start starts listening for incoming requests on the specified port (e.g., ":8080").

func (*Goster) StartTLS added in v0.2.0

func (g *Goster) StartTLS(addr string, certFile string, keyFile string)

func (*Goster) StaticDir

func (g *Goster) StaticDir(dir string) (err error)

StaticDir sets the directory from which static files like .css, .js, etc are served.

It integrates the specified directory into the server's static file handling by invoking AddStaticDir on the Routes collection.

If an error occurs during this process, the error is printed to the standard error output. The function returns the error encountered, if any.

func (*Goster) TemplateDir

func (g *Goster) TemplateDir(d string) (err error)

TemplateDir extends the engine's file paths with the specified directory `d`, which is joined to Engine.Config.BaseStaticDir (default is the execution path of the program).

This instructs the engine where to look for template files like .html, .gohtml. If the directory doesn't exist, it will return an appropriate error.

func (*Goster) Use

func (g *Goster) Use(path string, m ...RequestHandler)

Use adds middleware handlers that will be applied to specific routes/paths.

func (*Goster) UseGlobal

func (g *Goster) UseGlobal(m ...RequestHandler)

UseGlobal adds middleware handlers that will be applied to every single incoming request.

type Meta

type Meta struct {
	Query Params
	Path  Path
}

func (*Meta) ParsePath added in v0.2.0

func (m *Meta) ParsePath(url, urlPath string)

func (*Meta) ParseQueryParams added in v0.2.0

func (m *Meta) ParseQueryParams(url string)

Pass in a `url` and see if there're parameters in it

If there're, ParseQueryParams will construct a Params struct and populate Meta.Query.Params

If there aren't any, ParseQueryParams will return

The `url` string reference that is passed in will have the parameters stripped in either case

type Params

type Params map[string]string

func (*Params) Get

func (p *Params) Get(id string) (value string, exists bool)

Get tries to find if `id` is in the URL's Query Params

If the specified `id` isn't found `exists` will be false

type Path

type Path map[string]string

func (*Path) Get

func (p *Path) Get(id string) (value string, exists bool)

Get tries to find if `id` is in the URL's as a Dynamic Path Identifier

If the specified `id` isn't found `exists` will be false

type PathValues added in v0.2.0

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

type RequestHandler

type RequestHandler func(ctx *Ctx) error

RequestHandler is a type for functions that handle HTTP requests within a given context.

type Response

type Response struct {
	http.ResponseWriter
}

func (*Response) NewHeaders

func (r *Response) NewHeaders(h map[string]string, s int)

Supply h with a map[string]string for the headers and s with an int representing the response status code or use the http.Status(...). They keys and values will be translated to the header of the response and the header will be locked afterwards not allowing changes to be made.

type Route

type Route struct {
	Type    string         // Type specifies the type of the route (e.g., TypeStatic, TypeDynamic, TypeWildcard).
	Handler RequestHandler // Handler is the function that handles the route.
}

Route represents an HTTP route with a type and a handler function.

type Routes

type Routes map[string]map[string]Route

func (*Routes) New

func (rs *Routes) New(method string, url string, handler RequestHandler) (err error)

New creates a new Route for the specified method and url using the provided handler. If the Route already exists an error is returned.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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