Skip to content

zttp is a lightweight, zero-dependency, extremely fast, Go-based backend framework implemented over raw TCP sockets.

License

Notifications You must be signed in to change notification settings

muhammadzkralla/zttp

Repository files navigation

ZTTP

Introduction

ZTTP is a lightweight, zero-dependency, and extremely fast backend framework written in Go, built directly over raw TCP sockets. Designed as a toy project for educational purposes, it draws inspiration from modern web frameworks like Gofiber and Express.js.

This project follows the Front Controller design pattern, a widely adopted architectural approach in web frameworks such as Spring Boot, Express.js, and more.

All incoming TCP connections are funneled concurrently through a centralized request handling function handleClient(), which performs the following responsibilities:

  • Parses the HTTP request (method, path, params, queries, headers, body, cookies, etc.).
  • Extracts query parameters and dynamic route parameters.
  • Matches the request to a registered route handler using method and path.
  • Delegates the request to the matched handler with a unified request/response context.
  • Centrally Manages errors, timeouts, middlewares, connection lifecycle, and more.

By applying this pattern, the application enforces a clean separation of concerns, consistent request preprocessing, and centralized control over the request lifecycle. This design simplifies extensibility (e.g., adding middleware, authentication, logging) and improves maintainability as the application scales.

To state some numbers, I tested the same routes and benchmarks with different frameworks using wrk and took the average:

  • 300k RPS, 3.5 ms latency using GoFiber
  • 135k RPS, 8.7 ms latency using ZTTP
  • 67k RPS, 34 ms latency using Spring WebMVC
  • 55k RPS, 19 ms latency using Spring WebFlux
  • 10k RPS, 135 ms latency using Express.js (Node)
  • 1.7k RPS, 128 ms latency using Flask

zttp_graph


Benchmarks included different core numbers, time periods, routes, etc, all on the same machine separately, and those are the average values.

Why ZTTP?

ZTTP was created as a deep-dive into how web frameworks work under the hood. From TCP socket handling and manual HTTP parsing to request routing and middleware architecture. It is a hands-on exercise in systems-level web development using Go, with minimal abstractions.

I decided not to use any external HTTP engines, not even Go's net/http standard library, and handle all the logic from scratch starting from the TCP layer to gain maximum knowledge and experience.

Everything in this project is perfectly aligned with the RFC standards and HTTP/1.1 structure, as I spent days reading the RFC standards specific to each feature before starting to implement it.

Whether you're learning how the web works or exploring Go's networking capabilities, ZTTP is designed to be small enough to understand yet expressive enough to grow.

Installation

To use ZTTP in your Go project, simply run:

go get github.com/muhammadzkralla/zttp

Then, import it in your code:

import "github.com/muhammadzkralla/zttp"

Note

ZTTP is still under active development and may lack some features. It fetches the latest commit from the master branch. Semantic versioning and releases will be introduced later when I feel it's ready.

Usage

Here’s a minimal example of how to spin up a simple ZTTP server:

package main

import (
	"github.com/muhammadzkralla/zttp"
)

func main() {
	app := zttp.NewApp()

	app.Get("/", func(req *zttp.Req, res *zttp.Res) {
		res.Status(200).Send("Hello from ZTTP!")
	})

	app.Start(8080)
}

You can now test your server like this:

curl "localhost:8080"

You will get this printed in your terminal:

Hello from ZTTP!

Features

Core Functionality

  • Raw TCP HTTP/1.1 server with concurrent connection handling
  • Front Controller Design Pattern implementation
  • Zero dependency (pure GO standard library)

Routing

app.Get("/path", handler)
app.Post("/path", handler)
app.Put("/path", handler)
app.Patch("/path", handler)
app.Delete("/path", handler)

Path Parameters

// Route: "/post/:postId/comment/:commentId"
params := req.Params                // All params (map[string]string)
postId := req.Param("postId")       // postId param
commentId := req.Param("commentId")  // commentId param

Queries Parameters

// URL: /user?name=John&age=30
queries := req.Queries              // All queries (map[string]string)
name := req.Query("name")           // name query
age := req.Query("age")           // age query

Request Handling

  • Body parsing: req.Body (raw string)
body := req.Body    // raw string request body
  • JSON parsing:
// Parse request body into JSON and store the result in user variable
var user User
err := req.ParseJson(&user)
  • Form data & file uploads:
value := req.FormValue("field")     // Get `field` part from request
file, err := req.FormFile("file")   // Get `file` part from request
err = req.Save(file, "./uploads")   // Save file to disk in `./uploads` directory
  • Accept headers processing:
log.Println(req.Accepts("html"))                         // "html"
log.Println(req.AcceptsCharsets("utf-16", "iso-8859-1")) // "iso-8859-1"
log.Println(req.AcceptsEncodings("compress", "br"))      // "compress"
log.Println(req.AcceptsLanguages("en", "nl", "ru"))      // "nl"

And more request processing utilities.

Response Handling

  • Sending Response:
res.Status(201).Send("text")        // Text response
res.Status(200).Json(data)          // JSON response
res.Status(304).End()               // Empty response
  • Setting the Vary Response Header:
res.Vary("Accept-Encoding")         // Sets the `Vary` HTTP response header
  • Setting the Content-Type Response Header:
res.Type("application/json")        // Sets the `Content-Type` HTTP response header to the MIME type specified

And more response processing utilities.

Headers

req.Headers                         // All request headers (map[string]string)
res.Headers                         // All response headers (map[string][]string)
req.Header("Header-Name")           // Get request header
res.Header("Key", "Value")         // Set response header

Cookies

req.Cookies                     // All request cookies (map[string]string)
res.SetCookie(zttp.Cookie{      // Set response cookie
    Name: "session",
    Value: "token",
    Expires: time.Now().Add(24*time.Hour)
})

res.ClearCookie("username")	// Clear the username cookie

Static File Serving

res.Static("index.html", "./public")         // Serve HTML file
res.Static("image.png", "./assets")         // Serve image file

Middleware

// Global middleware
app.Use(func(req *zttp.Req, res *zttp.Res, next func()) {
    // Pre-processing
    next()
    // Post-processing
})

// Route-specific middleware
app.Use("/path", middlewareHandler)

Sub-Routers

router := app.NewRouter("/api/v1")
router.Get("/endpoint", handler)    // Handles /api/v1/endpoint
router.Use("/path", middlewareHandler) // Router-specific middleware

Cache Control

res.Header("ETag", "version1")
res.Header("Last-Modified", timestamp)

// If the request is still fresh in the client's cache
if req.Fresh() {
    // Handle cached responses, return 304 Not Changed response
    res.Status(304).End()
}

Error Handling

  • Automatic panic recovery
  • Manual error responses:
res.Status(400).Send("Bad request")

HTTPS Support via TLS

// Start secure server with TLS
app.StartTLS(443, "cert.pem", "key.pem")

For More details, visit the examples section.

About

zttp is a lightweight, zero-dependency, extremely fast, Go-based backend framework implemented over raw TCP sockets.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages