> ## Documentation Index
> Fetch the complete documentation index at: https://docs.neuro-tech.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Binding and responses

> Learn how the router binds route, query, and body values and turns return values into JSON

## The default binding model

For attributed controller methods, the router infers where values come from:

* For `POST`, `PUT`, and `PATCH`, one class-type parameter is treated as the request body
* Parameters whose names match route placeholders are read from the route
* Remaining scalar parameters are read from the query string

## Implicit binding example

```csharp theme={null}
[Controller]
[Route("/orders")]
public sealed class OrdersController : ControllerBase
{
    [HttpPost("/[orderId]")]
    public Task<OrderResponse> Update(OrderUpdate Body, string OrderId, string? Sort)
    {
        return Task.FromResult(new OrderResponse
        {
            OrderId = OrderId,
            Sort = Sort,
            Description = Body.Description
        });
    }
}

public sealed class OrderUpdate
{
    public string Description { get; set; } = string.Empty;
}

public sealed class OrderResponse
{
    public string OrderId { get; set; } = string.Empty;
    public string? Sort { get; set; }
    public string Description { get; set; } = string.Empty;
}
```

* `Body` — from the JSON body
* `OrderId` — from `/orders/[orderId]`
* `Sort` — from `?sort=...`

## Explicit binding example

```csharp theme={null}
[HttpPost("/[orderId]")]
public Task<OrderResponse> Update(
    [FromBody] OrderUpdate Body,
    [FromRoute] string OrderId,
    [FromQuery] string? Sort)
{
    return Task.FromResult(new OrderResponse
    {
        OrderId = OrderId,
        Sort = Sort,
        Description = Body.Description
    });
}
```

Explicit attributes:

* `[FromBody]`
* `[FromRoute]`
* `[FromQuery]`

## Important binding rules

* Only one body parameter is allowed
* `[FromBody]` is only valid on `POST`, `PUT`, and `PATCH`
* `[FromBody]` must target a class-type parameter
* Missing required route or query values return `400 Bad Request`
* Nullable query parameters can be omitted and bind as `null`

Route placeholder names and query string names are matched case-insensitively.

Body field names are different: they are decoded through the active `IParameterNameCodec`, so the JSON payload must follow the router's configured naming convention.

## Built-in conversions beyond strings

The current binder supports more than just basic strings and body objects.

* Enums can bind from route values, query values, and body fields
* `DateTimeOffset`, `DateOnly`, `TimeOnly`, and `TimeSpan` can bind from route, query, and body data when the incoming value is convertible

```csharp theme={null}
[HttpGet("/reports")]
public Task<ReportRequest> Get(DateOnly Date, TimeOnly Time, TimeSpan Duration)
{
    return Task.FromResult(new ReportRequest
    {
        Date = Date,
        Time = Time,
        Duration = Duration
    });
}
```

## Transport validation attributes

The current binding pipeline also validates parameters and bound body models before the controller action runs.

```csharp theme={null}
[HttpGet("/string-length")]
public Task<string> GetValidatedSearch([StringLength(2, 5)] string Search)
{
    return Task.FromResult(Search);
}

[HttpPost("/body")]
public Task<ValidatedBindingResult> PostValidatedBody(ValidatedBindingBody Body)
{
    return Task.FromResult(new ValidatedBindingResult
    {
        Title = Body.Title,
        ContactEmail = Body.ContactEmail,
        Attachments = Body.Attachments,
        PublicationDate = Body.PublicationDate?.ToString("O", CultureInfo.InvariantCulture)
    });
}

public sealed class ValidatedBindingBody
{
    [NonEmpty]
    public string Title { get; set; } = string.Empty;

    [EmailFormat]
    public string ContactEmail { get; set; } = string.Empty;

    [UrlFormat(ValidateElements = true)]
    public string[] Attachments { get; set; } = Array.Empty<string>();

    [NonDefault]
    public DateTimeOffset? PublicationDate { get; set; }
}
```

Available transport validation attributes include:

* `NonEmpty`
* `NonDefault`
* `StringLength(min, max)`
* `Range(min, max)`
* `EmailFormat`
* `UrlFormat`

Use `ValidateElements = true` on collection validators when each element should be checked individually.

When validation fails, the router returns `400 Bad Request` before the controller action runs.

## Returning JSON

Non-raw controller methods should return `Task<T>`. The returned object is serialized to JSON automatically.

```csharp theme={null}
[HttpGet("/[userId]")]
public Task<UserResponse> Get(string UserId)
{
    return Task.FromResult(new UserResponse
    {
        UserId = UserId,
        DisplayName = "Ada"
    });
}
```

## Returning errors

For attributed methods, throw an HTTP exception:

```csharp theme={null}
[HttpGet("/[userId]")]
public Task<UserResponse> Get(string UserId)
{
    if (UserId == "missing")
        throw new NotFoundException(new RestApiErrorResponse("User not found.", "user_not_found"));

    if (UserId == "bad")
        throw new BadRequestException(new RestApiErrorResponse("User id is invalid.", "invalid_user_id"));

    return Task.FromResult(new UserResponse
    {
        UserId = UserId,
        DisplayName = "Ada"
    });
}
```

Useful helpers:

* `RestApiErrorResponse` — simple `{ message, error_code }` payload
* `ClientError` — carries status code, message, localization key, and error code
* `Expected<T, E>` — models success and failure explicitly before converting to HTTP

If an unexpected exception escapes the controller, the router converts it into an internal server error with code `internal_server_exception`.

<Note>
  Validation field paths use the active parameter-name codec for body properties. If you switch to snake case, validation messages follow that same JSON-facing naming.
</Note>

## What to read next

[Middleware and pipeline](/neuron-development/first-party-packages/neuron-http-router/middleware-and-pipeline) shows how to add cross-cutting behavior before and after your endpoints run.
