Loading…
A simple and minimalist web framework for Go, built entirely from scratch. Squirrel provides a lightweight HTTP server with routing, middleware support, and request/response handling while keeping the API simple, fast, and developer-friendly
Squirrel Framework is a lightweight and minimalist web framework for Go (Golang), designed and implemented entirely from scratch using Go's standard library and low-level networking primitives.
The primary goal of Squirrel is to provide the essential building blocks required to develop HTTP applications without introducing unnecessary complexity. Its design is inspired by the simplicity and developer experience of popular Go web frameworks such as Gin, but Squirrel focuses on maintaining a smaller and easier-to-understand internal architecture.
Rather than hiding the underlying HTTP concepts behind a large abstraction layer, Squirrel provides a thin framework around HTTP request handling, routing, middleware, and response generation.
The framework currently provides a lightweight HTTP server implementation with:
The project was built purely with Go, making it a useful exploration of how HTTP servers and web frameworks can be constructed from lower-level networking primitives.
Squirrel is built around three primary principles:
The framework should remain small enough that developers can understand how its major components work without navigating through a large abstraction hierarchy.
Squirrel avoids unnecessary dependencies and provides only the fundamental components required for building HTTP applications.
Although the framework operates close to the underlying networking layer, its public API is designed to make common web-development tasks straightforward.
The intention is not to compete with large production frameworks in terms of features. Instead, Squirrel focuses on providing a compact foundation that demonstrates how routing, middleware, request processing, and response handling can work together.
At its core, Squirrel can be viewed as a pipeline:
Incoming HTTP Connection
↓
Request Parsing
↓
Route Matching
↓
Middleware Chain
↓
Route Handler
↓
Response Generation
↓
HTTP Response
An incoming connection is processed and transformed into a Request object. The framework then determines which route matches the request and constructs the appropriate middleware chain.
The final handler receives both the request and response objects, allowing the application to read incoming data and construct the outgoing response.
The Request structure represents an incoming HTTP request.
type Request struct {
Conn net.Conn
Method string
Path string
Body io.ReadCloser
Headers map[string]string
Url *url.URL
Params map[string]string
ContentLength int64
Close bool
Queries map[string][]string
Cookies []*cookies.Cookie
}
The structure provides access to the major pieces of information associated with an HTTP request.
Conn
Contains the underlying network connection associated with the request.
Method
Stores the HTTP method, such as GET, POST, PUT, PATCH, or DELETE.
Path
Contains the requested URL path.
Body
An io.ReadCloser that allows the application to read request-body data. This makes it possible to work with different types of request payloads rather than restricting the framework to a single data format.
Headers
Stores HTTP request headers as key-value pairs.
Url
Contains the parsed URL represented by Go's url.URL type.
Params
Contains parameters extracted from the matched route.
For example, a route such as:
/users/:id
could result in:
req.Params["id"]
containing the corresponding value from the requested URL.
ContentLength
Contains the size of the request body when available.
Close
Represents whether the underlying connection should be closed after processing the request.
Queries
Stores query parameters and supports multiple values for the same query key through:
map[string][]string
Cookies
Contains parsed request cookies.
The Response structure represents the server's response to the client.
type Response struct {
conn net.Conn
headers map[string]string
contentType string
body io.ReadCloser
statusCode int
cookies []*cookies.Cookie
}
The response abstraction is responsible for constructing and eventually writing the HTTP response back to the client.
conn
Maintains the underlying network connection used to send the response.
headers
Stores response headers that will be included in the HTTP response.
contentType
Represents the content type of the response body.
body
Contains the response body as an io.ReadCloser.
statusCode
Stores the HTTP status code returned to the client.
cookies
Contains cookies that should be included in the response.
This separation between request and response objects allows handlers to focus on application logic rather than directly manipulating the underlying connection for every operation.
Squirrel defines a simple handler function signature:
type HandlerFunc func(req *Request, res *Response)
A handler receives both the incoming request and the response that will be sent back to the client.
For example:
func hello(req *Request, res *Response) {
// Handle request
// Build response
}
This provides a minimal interface between the framework's HTTP processing pipeline and application-level logic.
The handler does not need to directly manage the complete lifecycle of the network connection. Instead, it works with Squirrel's request and response abstractions.
Routing is one of the central components of Squirrel.
The framework maintains route information internally using a structure similar to:
type route struct {
method string
pattern string
handler core.HandlerFunc
middleware []Middleware
}
Each route stores:
This design allows the framework to associate middleware directly with individual routes rather than requiring every middleware component to be globally applied.
For example, an application could conceptually have routes such as:
GET /users
GET /users/:id
POST /users
DELETE /users/:id
The router determines which registered route corresponds to the incoming HTTP request and passes the request to its associated handler.
Squirrel supports route-specific parameters through the request's Params map.
A route can define a dynamic section of its path, allowing values from the URL to become available to the handler.
Conceptually:
/users/:id
A request such as:
/users/42
can expose:
req.Params["id"]
with the value:
42
This provides a convenient mechanism for implementing resource-oriented APIs.
Middleware is another fundamental part of Squirrel's architecture.
The framework defines middleware using:
type Middleware func(HandlerFunc) HandlerFunc
This follows the common middleware pattern where a middleware function receives a handler and returns another handler.
Conceptually:
Request
↓
Middleware A
↓
Middleware B
↓
Route Handler
Each middleware can execute logic before and/or after passing control to the next handler.
This architecture makes it possible to implement cross-cutting functionality such as:
Squirrel also supports route-specific middleware, allowing different routes to have different middleware chains.
For example, an authentication middleware could be applied only to protected routes instead of being executed for every request.
One of the goals of Squirrel is to keep request and response handling explicit and lightweight.
The request abstraction exposes the information needed by application code, including:
Similarly, the response abstraction provides the mechanisms required to construct an HTTP response, including:
By keeping these concerns separated, the framework creates a clear boundary between HTTP processing and application logic.
Unlike frameworks that primarily wrap an existing high-level HTTP abstraction, Squirrel makes use of lower-level Go networking concepts such as:
net.Conn
This gives the project a closer relationship with the underlying HTTP server lifecycle.
Working at this level also makes the framework a useful exploration of:
This approach keeps the framework lightweight while also providing greater insight into what happens underneath a typical web framework.
A Squirrel application can conceptually follow a simple structure:
Application
│
├── Server
│
├── Router
│ ├── Route
│ ├── Route
│ └── Route
│
├── Middleware
│ ├── Middleware
│ └── Middleware
│
└── Handlers
├── Handler
├── Handler
└── Handler
An incoming request enters the server, gets converted into a request representation, passes through routing and middleware, and eventually reaches the corresponding application handler.
Squirrel was built as a practical exploration of how a web framework works internally.
Instead of simply using an existing framework, the project focuses on understanding and implementing the fundamental components that make frameworks such as Gin convenient for developers.
Building Squirrel from scratch provided an opportunity to work directly with:
The project therefore serves both as a usable lightweight framework and as an exercise in understanding the architecture behind modern Go web frameworks.
| Feature | Squirrel |
|---|---|
| Language | Go |
| Architecture | Lightweight HTTP framework |
| HTTP Server | Custom lightweight implementation |
| Routing | Supported |
| Route Parameters | Supported |
| Middleware | Supported |
| Route-specific Middleware | Supported |
| Request Body | Supported |
| Headers | Supported |
| Query Parameters | Supported |
| Cookies | Supported |
| Response Status | Supported |
| Response Headers | Supported |
| External Framework Dependencies | Minimal / none |
| Design Goal | Simple, lightweight, developer-friendly |
Squirrel Framework is a compact web framework for Go that focuses on understanding and implementing the fundamental components of HTTP application development.
Built entirely in Go, the framework combines a lightweight HTTP server implementation with routing, middleware composition, request/response abstractions, route parameters, query handling, headers, and cookies.
Rather than attempting to provide every feature found in mature production frameworks, Squirrel intentionally keeps its architecture small and understandable. Its design is inspired by the developer experience of frameworks such as Gin while maintaining its own minimal implementation.
The project demonstrates how a functional web framework can be constructed from relatively small and well-defined components, while also providing a foundation that can be extended with additional capabilities in the future.