> For the complete documentation index, see [llms.txt](https://azutopia.gitbook.io/azu/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://azutopia.gitbook.io/azu/api-reference/router.md).

# Router

The router handles HTTP request routing using a radix tree for high performance.

## Route Registration

Routes are automatically registered when defining endpoints:

```crystal
struct MyEndpoint
  include Azu::Endpoint(EmptyRequest, MyResponse)

  get "/path"  # Registers GET /path

  def call : MyResponse
    # Handle request
  end
end
```

## Route Patterns

### Static Routes

```crystal
get "/"
get "/users"
get "/api/v1/health"
```

### Dynamic Parameters

```crystal
get "/users/:id"           # Single parameter
get "/posts/:id/comments"  # Parameter in middle
get "/:category/:slug"     # Multiple parameters
```

### Wildcard Routes

```crystal
get "/files/*path"  # Captures rest of path
```

## HTTP Methods

| Method  | Macro     | Description       |
| ------- | --------- | ----------------- |
| GET     | `get`     | Retrieve resource |
| POST    | `post`    | Create resource   |
| PUT     | `put`     | Replace resource  |
| PATCH   | `patch`   | Update resource   |
| DELETE  | `delete`  | Remove resource   |
| OPTIONS | `options` | Get options       |
| HEAD    | `head`    | Get headers only  |

## Route Matching

Routes are matched in order of specificity:

1. Exact static matches
2. Parameterized routes
3. Wildcard routes

```crystal
get "/users"          # Matches /users exactly
get "/users/:id"      # Matches /users/123
get "/users/*rest"    # Matches /users/123/posts/456
```

## Accessing Route Parameters

```crystal
get "/users/:id/posts/:post_id"

def call
  user_id = params["id"]        # => "123"
  post_id = params["post_id"]   # => "456"
end
```

### Wildcard Parameters

```crystal
get "/files/*path"

def call
  path = params["path"]  # => "docs/readme.md"
end
```

## Route Constraints

### Custom Constraints

```crystal
# Only match numeric IDs
get "/users/:id" do
  constraint :id, /^\d+$/
end
```

## Router Configuration

### Path Caching

Enable path caching for performance:

```crystal
Azu.configure do |config|
  config.router.path_cache_size = 1000  # Cache 1000 paths
end
```

## Router API

### routes

Get all registered routes.

```crystal
Azu.router.routes.each do |route|
  puts "#{route.method} #{route.path}"
end
```

### find

Find a route for a request.

```crystal
route = Azu.router.find("GET", "/users/123")
route.handler  # => Handler
route.params   # => {"id" => "123"}
```

## Route Groups

Organize routes with common prefixes:

```crystal
# Define multiple endpoints with shared prefix
struct ApiV1::UsersIndex
  include Azu::Endpoint(EmptyRequest, UsersResponse)
  get "/api/v1/users"
end

struct ApiV1::UsersShow
  include Azu::Endpoint(EmptyRequest, UserResponse)
  get "/api/v1/users/:id"
end
```

## Performance

The router uses a radix tree (Radix) for O(k) route matching where k is the path length.

### Benchmarks

* Static routes: \~150ns
* Dynamic routes: \~200ns
* Wildcard routes: \~250ns

### Optimization Tips

1. Put most common routes first in handler chain
2. Enable path caching for repeated paths
3. Use static paths when possible

## Error Handling

### Not Found

When no route matches:

```crystal
# Handler::Rescuer returns 404
{
  "error": "Not Found",
  "path": "/unknown"
}
```

### Method Not Allowed

When path matches but method doesn't:

```crystal
# Returns 405 with Allow header
{
  "error": "Method Not Allowed",
  "allowed": ["GET", "POST"]
}
```

## Complete Example

```crystal
# User CRUD endpoints
struct UsersIndex
  include Azu::Endpoint(EmptyRequest, UsersResponse)
  get "/users"
end

struct UsersShow
  include Azu::Endpoint(EmptyRequest, UserResponse)
  get "/users/:id"
end

struct UsersCreate
  include Azu::Endpoint(CreateUserRequest, UserResponse)
  post "/users"
end

struct UsersUpdate
  include Azu::Endpoint(UpdateUserRequest, UserResponse)
  put "/users/:id"
end

struct UsersDelete
  include Azu::Endpoint(EmptyRequest, Azu::Response::Empty)
  delete "/users/:id"
end

# Nested routes
struct UserPosts
  include Azu::Endpoint(EmptyRequest, PostsResponse)
  get "/users/:user_id/posts"
end

struct UserPostShow
  include Azu::Endpoint(EmptyRequest, PostResponse)
  get "/users/:user_id/posts/:id"
end
```

## See Also

* [Endpoint Reference](/azu/api-reference/endpoint.md)
* [Handler Reference](/azu/handlers/built-in.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://azutopia.gitbook.io/azu/api-reference/router.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
