netio

package module
v1.1.8 Latest Latest
Warning

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

Go to latest
Published: Mar 24, 2026 License: MIT Imports: 17 Imported by: 0

README

NetIO – Lightweight HTTP Library for Go

NetIO is a fast, minimalistic HTTP library built on top of native TCP connections. It provides flexible routing, middleware support, automatic JSON parsing, and efficient context management – all without external dependencies.

✨ Features

  • 🚀 High‑performance, zero‑dependency core
  • 🛣️ Path parameter routing (e.g., /users/:id)
  • 🔗 Global and per‑route middleware
  • 📦 Automatic JSON body parsing & responses
  • 🔍 Query string, header, and path parameter binding to structs
  • 📁 Multipart file upload support
  • 🌐 Built‑in CORS middleware
  • ⚙️ Configurable maximum request body size
  • 🧠 Optimised context pooling for low latency

📦 Installation

go get github.com/atendi9/netio

🚀 Quick Start

package main

import (
    "encoding/json"
    "log"

    "github.com/atendi9/netio"
    "github.com/atendi9/netio/cors"
)

func main() {
    app, err := netio.New(netio.AppConfig{
        Port:        "8080",
        AppName:     "myapp",
        MaxBodySize: "10 MB",
    })
    if err != nil {
        log.Fatal(err)
    }

    // Global middleware
    app.Use(cors.Middleware(cors.Config{
        AllowOrigins: []string{"*"},
    }))

    app.Use(func(c *netio.Context) {
        log.Printf("Method=%s Path=%s IP=%s", c.Method(), c.Path(), c.IP())
        c.Next()
    })

    // POST route
    app.POST("/", func(c *netio.Context) {
        body := c.Body()
        log.Println(string(body))
        c.JSON(map[string]any{"message": "Hello World"})
    })

    // GET route
    app.GET("/", func(c *netio.Context) {
        c.Send([]byte(`{"message":"Hello World"}`))
    })

    app.Listen()
}

⚙️ Configuration

AppConfig controls the server’s behaviour:

type AppConfig struct {
    Port        string      // listening port (required)
    AppName     string      // application name for logs (optional)
    MaxBodySize MaxBodySize // max body size, e.g., "15 MB", "500 KB"
}
  • MaxBodySize supports units: B, KB, MB, GB, TB. Default is "15 MB".

🛣️ Routing

NetIO supports the common HTTP methods:

  • GET
  • POST
  • PUT
  • DELETE
  • PATCH
Path Parameters

Parameters are defined with a colon prefix:

app.GET("/users/:id", func(c *netio.Context) {
    userID := c.Param("id")
    c.JSON(map[string]string{"user_id": userID})
})

app.GET("/users/:id/posts/:postId", func(c *netio.Context) {
    userID := c.Param("id")
    postID := c.Param("postId")
    c.JSON(map[string]string{
        "user_id": userID,
        "post_id": postID,
    })
})

🔧 Middleware

Global Middleware

Add middleware that runs for every request:

app.Use(func(c *netio.Context) {
    // before request
    log.Println("before")
    c.Next()
    // after request (if any)
    log.Println("after")
})
CORS Middleware

Import the cors subpackage:

import "github.com/atendi9/netio/cors"

app.Use(cors.Middleware(cors.Config{
    AllowOrigins:     []string{"http://localhost:3000"},
    AllowMethods:     []string{"GET", "POST", "PUT", "DELETE"},
    AllowHeaders:     []string{"Content-Type", "Authorization"},
    ExposeHeaders:    []string{"Content-Length"},
    AllowCredentials: true,
}))

📝 The Context Object

The Context holds all request/response data and provides helper methods.

Request Data
// HTTP method
method := c.Method()

// Path (with optional default)
path := c.Path() // or c.Path("/fallback")

// Headers
allHeaders := c.Headers()
userAgent := c.Header("User-Agent")

// Raw body
body := c.Body() // []byte

// Client IP
ip := c.IP()
ips := c.IPs() // X-Forwarded-For + direct IP

// Query parameters
name := c.Query("name", "default")
c.QueryParser(&struct {
    Name string `query:"name"`
    Age  int    `query:"age"`
}{})
Path Parameters
// Direct access
userID := c.Param("id")

// Parse into struct
type UserParams struct {
    UserID string `param:"id"`
    PostID string `param:"postId"`
}
var params UserParams
c.ParamsParser(&params)
Request Body Parsing
type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

var user User
if err := c.BodyParser(&user); err != nil {
    c.SendStatus(400)
    return
}
Header Parsing
type AuthHeaders struct {
    Authorization string `header:"Authorization"`
    XRequestID    string `header:"X-Request-ID"`
}

var headers AuthHeaders
c.ReqHeaderParser(&headers)
Responses
// Send JSON
c.JSON(map[string]string{"status": "ok"})

// Send raw bytes
c.Send([]byte("Hello"))

// Send only status code
c.SendStatus(204)

// Set response header
c.HeaderSet("X-Custom", "value")
File Upload
app.POST("/upload", func(c *netio.Context) {
    file, err := c.FormFile("file")
    if err != nil {
        c.SendStatus(400)
        return
    }

    // *multipart.FileHeader
    log.Printf("Received: %s (%d bytes)", file.Filename, file.Size)

    c.JSON(map[string]string{"status": "uploaded"})
})

⚖️ Body Size Limiting

Set the maximum allowed request body size in AppConfig. Requests exceeding the limit receive a 413 Payload Too Large response.

app, _ := netio.New(netio.AppConfig{
    Port:        "8080",
    MaxBodySize: "10 MB", // default is "15 MB"
})

📊 Logging

On startup, NetIO logs the server address:

myapp ▷ http.server is running
myapp ▷ http://localhost:8080

🎯 Advanced Examples

Complete REST API
type User struct {
    ID   string `json:"id"`
    Name string `json:"name"`
    Age  int    `json:"age"`
}

// GET /users/:id
app.GET("/users/:id", func(c *netio.Context) {
    id := c.Param("id")
    user := User{ID: id, Name: "John", Age: 30}
    c.JSON(user)
})

// POST /users
app.POST("/users", func(c *netio.Context) {
    var user User
    if err := c.BodyParser(&user); err != nil {
        c.SendStatus(400)
        return
    }
    // store user...
    c.SendStatus(201)
})

// PUT /users/:id
app.PUT("/users/:id", func(c *netio.Context) {
    id := c.Param("id")
    var user User
    if err := c.BodyParser(&user); err != nil {
        c.SendStatus(400)
        return
    }
    user.ID = id
    c.JSON(user)
})

// DELETE /users/:id
app.DELETE("/users/:id", func(c *netio.Context) {
    id := c.Param("id")
    // delete user...
    c.JSON(map[string]string{"deleted": id})
})

📄 License

MIT License – see LICENSE for details.


Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidSize              = errors.New("invalid maxBodySize")
	ErrUnknowUnit               = errors.New("unknown unit")
	ErrInvalidMaxBodySizeFormat = errors.New("invalid format")
)
View Source
var ErrAborted = errors.New("aborted")
View Source
var ErrDstMustBeAPointer = errors.New("dst must be pointer")
View Source
var ErrEmptyBody = errors.New("empty body")
View Source
var ErrFormFileNotFound = errors.New("form file not found")

Functions

This section is empty.

Types

type App

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

App represents a netio HTTP application.

func New

func New(config AppConfig) (*App, error)

New creates a new App instance based on AppConfig.

func (*App) DELETE

func (a *App) DELETE(path string, h ...Handler)

DELETE registers a DELETE route with handlers.

func (*App) GET

func (a *App) GET(path string, h ...Handler)

GET registers a GET route with handlers.

func (*App) Group added in v1.1.1

func (a *App) Group(basePath string, m ...Handler) Router

Group creates a new route group with a common base path and middleware.

All routes registered within this group will be prefixed with basePath, and the provided middlewares will be executed before the route handlers.

Groups can be nested, and child groups inherit both the path prefix and middleware stack from their parent.

func (*App) Listen

func (a *App) Listen() error

Listen starts the HTTP server on the configured port.

func (*App) PATCH

func (a *App) PATCH(path string, h ...Handler)

PATCH registers a PATCH route with handlers.

func (*App) POST

func (a *App) POST(path string, h ...Handler)

POST registers a POST route with handlers.

func (*App) PUT

func (a *App) PUT(path string, h ...Handler)

PUT registers a PUT route with handlers.

func (*App) Shutdown added in v1.1.1

func (a *App) Shutdown(ctx context.Context) error

Shutdown gracefully stops the application listener when the context is done.

It blocks until the context is canceled or reaches its deadline, then closes the underlying network listener, causing any blocking Accept calls to return.

If the listener is not initialized, Shutdown returns nil.

func (*App) Use

func (a *App) Use(h Handler)

Use adds a global middleware handler.

type AppConfig

type AppConfig struct {
	Port        string
	AppName     string
	MaxBodySize MaxBodySize
}

AppConfig represents configuration options for a new App.

type Context

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

Context represents a single HTTP request/response cycle.

func (*Context) Abort

func (c *Context) Abort()

Abort stops the execution of the remaining handlers.

func (*Context) Body

func (c *Context) Body() []byte

Body returns the raw request body.

func (*Context) BodyParser

func (c *Context) BodyParser(v any) error

BodyParser parses the request body JSON into the given destination.

func (*Context) FormFile

func (c *Context) FormFile(key string) (*multipart.FileHeader, error)

FormFile retrieves an uploaded file from a multipart/form request.

func (*Context) Header

func (c *Context) Header(key string) string

Header returns the first value for the given header key.

func (*Context) HeaderSet

func (c *Context) HeaderSet(key, value string)

HeaderSet sets or replaces a header in the Context.

func (*Context) Headers

func (c *Context) Headers() map[string][]string

Headers returns all request headers as a map.

func (*Context) IP

func (c *Context) IP() string

IP returns the remote IP address of the connection.

func (*Context) IPs

func (c *Context) IPs() []string

IPs returns a slice of IPs from X-Forwarded-For or the remote IP.

func (*Context) JSON

func (c *Context) JSON(data any) error

JSON sends a JSON response.

func (*Context) Method

func (c *Context) Method() string

Method returns the HTTP method of the request as a string.

func (*Context) Next

func (c *Context) Next() error

Next executes the next handler in the Context's handler chain.

func (*Context) Now

func (c *Context) Now() time.Time

Now returns the current time.

func (*Context) Param

func (c *Context) Param(key string) string

Param returns a single path parameter by key.

func (*Context) Params

func (c *Context) Params(name string, defaultValue ...string) string

Params returns a path parameter value or a default if missing.

func (*Context) ParamsParser

func (c *Context) ParamsParser(v any) error

ParamsParser parses path parameters into a struct using `param` tags.

func (*Context) Path

func (c *Context) Path(defaultValue ...string) string

Path returns the request path, or a default value if empty.

func (*Context) Query

func (c *Context) Query(name string, defaultValue ...string) string

Query returns a query parameter value or a default if missing.

func (*Context) QueryParser

func (c *Context) QueryParser(v any) error

QueryParser parses query parameters into a struct using `query` tags.

func (*Context) ReqHeaderParser

func (c *Context) ReqHeaderParser(v any) error

ReqHeaderParser parses headers into a struct using `header` tags.

func (*Context) Send

func (c *Context) Send(data []byte) error

Send writes raw data to the response.

func (*Context) SendFile added in v1.1.3

func (c *Context) SendFile(filePath string)

SendFile reads a file from the given path and sends its content as the response.

If the file cannot be read, it sends the current status code without a body.

func (*Context) SendFileFromReader added in v1.1.3

func (c *Context) SendFileFromReader(r io.ReadCloser)

SendFileFromReader streams data directly to the underlying connection.

It uses io.Copy with net.Conn, which is efficient and avoids buffering the entire content in memory. Suitable for large payloads.

The reader is closed after the operation.

func (*Context) SendStatus

func (c *Context) SendStatus(status int) error

SendStatus sends an HTTP response with the given status code.

func (*Context) Status added in v1.1.3

func (c *Context) Status(statusCode int) *Context

Status sets the HTTP status code for the response.

It returns the current Context instance to allow method chaining.

Example:

ctx.Status(200).Send([]byte("ok"))

type Handler

type Handler func(c *Context)

Handler defines the signature for request handler functions that process a Context.

type KV

type KV struct {
	K []byte
	V []byte
}

KV represents a key-value pair.

type MaxBodySize

type MaxBodySize string

MaxBodySize is a string type for configuration of max body size.

func (MaxBodySize) String

func (s MaxBodySize) String() string

String returns the max body size as a string, with default "15 MB".

type Router added in v1.1.1

type Router interface {
	Get(path string, h ...Handler)
	Post(path string, h ...Handler)
	Put(path string, h ...Handler)
	Delete(path string, h ...Handler)
	Patch(path string, h ...Handler)

	// Group creates a new Router with the given path prefix and optional middleware.
	//
	// The returned Router inherits the current base path and middleware stack,
	// allowing nested groups for better route organization.
	Group(path string, m ...Handler) Router
	Use(h ...Handler)
}

Router defines a contract for registering HTTP routes and creating route groups.

A Router allows attaching handlers to specific HTTP methods and paths. It also supports grouping routes under a common path prefix with shared middleware.

Implementations should ensure that middlewares defined in groups are executed before route-specific handlers.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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