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
[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
[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
Returning JSON
Non-raw controller methods should return Task<T>. The returned object is serialized to JSON automatically.
[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:
[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.
What to read next
Middleware and Pipeline shows how to add cross-cutting behavior before and after your endpoints run.