Purpose of the Gitea Web Package: Core HTTP Routing and Middleware Architecture

The Gitea web package functions as the central HTTP routing and request-handling layer, wrapping the chi router to provide middleware orchestration, custom regex-based path groups, handler conversion utilities, and test-friendly mocking hooks that bridge incoming HTTP traffic to Gitea's business logic.

The web package in the go-gitea/gitea repository serves as the foundational infrastructure that transforms raw HTTP requests into structured, context-rich interactions with the Git service. Located primarily in modules/web/, this package abstracts the standard Go HTTP stack by handling URL normalization, route matching, and middleware injection before requests reach Gitea's business logic controllers.

Core Responsibilities of the Gitea Web Package

The web package consolidates several critical responsibilities that would otherwise be scattered across the codebase. According to the Gitea source code, these capabilities work together to create a testable, extensible routing layer.

Router Abstraction Around Chi

At its core, the package wraps the chi router to add Gitea-specific features such as middleware stacking, route groups, and path normalization. In modules/web/router.go, the Router type provides familiar methods like Get(), Post(), Any(), and Group() that forward to chi's underlying implementations after applying Gitea middleware patterns. The NewRouter() function creates isolated router instances, while Routes() returns the global router used for mounting sub-routers throughout the application.

Custom Path Groups for Complex Routing

Standard chi routing cannot express certain URL patterns required by Gitea, such as repository names with special characters. The modules/web/router_path.go file implements path groups via the PathGroup() method, which supports regex-based placeholders like <name>. The internal patternRegexp parser processes these custom syntaxes, enabling routes such as /repo/<owner>/<name> where segments match complex validation rules before hitting handlers.

Handler Conversion and Context Injection

The modules/web/handler.go file converts ordinary Go functions into "handler providers" compatible with Gitea's middleware expectations. This conversion injects a ResponseStatusProvider interface that allows the framework to detect whether a handler has already written a response, preventing duplicate writes. The package also exposes SetForm() and GetForm() utilities in modules/web/router.go that bind incoming request data to structs and store them in the request context for downstream handlers.

Test Mocking and Global Route Registration

To support unit testing without modifying production code, modules/web/routemock.go exposes RouterMockPoint hooks that tests can replace or extend. Meanwhile, routers/web/web.go serves as the top-level registry, assembling the complete web-router tree (static assets, API, UI, auth, admin) and wiring it with Gitea-wide middlewares including gzip, CORS, authentication, and locale handling.

Practical Code Examples

The following examples demonstrate how to interact with the Gitea web package for common routing scenarios.

Registering a Simple Route

Use web.NewRouter() to create a router instance and web.Routes() to access the global registry for mounting:

package myplugin

import (
	"net/http"

	"code.gitea.io/gitea/modules/web"
)

func MyHandler(resp http.ResponseWriter, req *http.Request) {
	_, _ = resp.Write([]byte("hello from my plugin"))
}

func Register() {
	r := web.NewRouter()
	r.Get("/myplugin/hello", MyHandler)
	web.Routes().Mount("", r)
}

Source reference: The Get method is defined in modules/web/router.go and forwards to chi's Method("GET", …) after applying middleware.

Implementing Regex-Based Path Groups

For routes requiring custom parameter validation, use PathGroup() with regex capture groups:

func RegisterCustomGroup() {
	r := web.NewRouter()
	r.Group("/repo", func() {
		r.PathGroup("/<owner>/<name>", func(g *web.RouterPathGroup) {
			g.MatchPath("GET", "/info", repoInfoHandler)
		})
	}, nil)
	web.Routes().Mount("", r)
}

Source reference: The PathGroup helper is implemented in modules/web/router_path.go; the <name> pattern syntax is parsed by patternRegexp.

Creating Custom Middleware with Form Binding

Middleware can inject parsed form data into the request context using SetForm():

func BindFormMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var payload MyForm
		if err := json.NewDecoder(r.Body).Decode(&payload); err == nil {
			web.SetForm(reqctx.GetData(r.Context()), &payload)
		}
		next.ServeHTTP(w, r)
	})
}

// Register with the router:
router.Use(BindFormMiddleware)

Source reference: SetForm and context management utilities live in modules/web/router.go and are consumed by the core web.Bind helper.

Key Source Files and Architecture

Understanding the file structure within the Gitea web package clarifies how requests flow from the HTTP server to business logic:

  • modules/web/router.go – Defines the main Router type, route registration helpers (Get, Post, Any, Group), and context utilities (SetForm, GetForm).
  • modules/web/handler.go – Converts ordinary functions to handler providers and manages the ResponseStatusProvider interface for response tracking.
  • modules/web/router_path.go – Implements the regex-based PathGroup functionality for advanced URL matching.
  • modules/web/routemock.go – Exposes RouterMockPoint and related structures for test-time middleware manipulation.
  • routers/web/web.go – Assembles the complete Gitea web router, attaches global middlewares, and mounts all feature-specific sub-routers.
  • modules/web/middleware/* – Contains various middleware implementations (locale, flash messages, data binding, cookies) that the router orchestrates.

Summary

The Gitea web package serves as the critical bridge between raw HTTP requests and the application's domain logic:

Frequently Asked Questions

What underlying router does the Gitea web package use?

The Gitea web package wraps the chi router, as implemented in modules/web/router.go. It forwards standard HTTP methods to chi after applying Gitea-specific middleware chains and path normalization.

How does the Gitea web package handle URL patterns that chi cannot express?

Through the PathGroup() method in modules/web/router_path.go, the package supports custom regex-based placeholders such as <name>. The internal patternRegexp parser processes these patterns, enabling complex routing rules for repository names and other variable segments.

Can developers use the Gitea web package for custom plugins or extensions?

Yes. Developers can call web.NewRouter() to create isolated router instances, register handlers using methods like Get() or Post(), and mount them into the global router via web.Routes().Mount(). This pattern allows plugins to integrate with Gitea's HTTP layer while leveraging its middleware infrastructure.

Where does Gitea register all its application routes?

The main route registration occurs in routers/web/web.go, which imports the modules/web package to build the complete router tree. This file wires together static asset serving, API endpoints, UI routes, and administrative interfaces while attaching global middlewares such as session handling, locale detection, and CSRF protection.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →