---
title: "Steel"
tagline: "HTTP router"
language: "Go"
license: "MIT"
since: "2025"
canonical: "https://xraph.com/work/steel"
---

# Steel

A Go router with typed handlers. Declare the request struct and you get path, query and body binding, validation, and an OpenAPI 3 document generated from the same types. WebSocket and SSE routes produce AsyncAPI. Forge’s router grew out of it.

## Install

```bash
go get github.com/xraph/steel
```

## What it is

A high-performance HTTP router for Go built on a radix tree, with zero allocations for parameter extraction, and with typed handlers that generate their own documentation.

## Opinionated handlers

Declare the request as a struct with path, query and json tags, and Steel binds and validates it, then generates OpenAPI 3.0 from the same types. There is no second description of the endpoint to fall out of date.

```go
r.OpinionatedGET("/users/:id", func(ctx *steel.Context, req User) (*UserResponse, error) {
    return &UserResponse{ID: req.ID, Name: req.Name}, nil
}, steel.WithSummary("Get User"), steel.WithTags("users"))

r.EnableOpenAPI()
```

## The rest

WebSocket and SSE support with AsyncAPI documentation, middleware with built-in recovery, logging and timeout, testing utilities with request builders and assertions, and doc UIs across Swagger, ReDoc, Scalar and Stoplight Elements.

Steel came before Forge by two days and Forge's router grew directly out of it. It is still useful on its own when you want the routing and the generated spec without the framework.

---

*Unpublished draft. Not peer reviewed and not submitted to a venue.*


## Anatomy

- **Router**: Radix routing with typed parameters.
- **Handlers**: Opinionated signatures: a request in, a value and an error out.
- **Middleware**: Composable, ordered, and scoped per route group.

## Constraints and trade-offs

- (decision) Handlers return values, not written responses. Serialisation is the framework’s job.
- (trade-off) The opinion is the point. A handler that wants full control of the writer should not use this.
