Controller-based APIs

ApiController attribute

The [ApiController] attribute can be applied to a controller class to enable the following opinionated, API-specific behaviors:

  • Attribute routing requirement

The [ApiController] attribute makes attribute routing a requirement.

Actions are inaccessible via conventional routes defined by UseEndpoints, UseMvc, or UseMvcWithDefaultRoute.

  • Automatic HTTP 400 responses

The [ApiController] attribute makes model validation errors automatically trigger an HTTP 400 response.

  • Binding source parameter inference

A binding source attribute defines the location at which an action parameter's value is found.

AttributeBinding source

[FromBody]

Request body

[FromForm]

Form data in the request body

[FromHeader]

Request header

[FromQuery]

Request query string parameter

[FromRoute]

Route data from the current request

[FromServices]

The request service injected as an action parameter

  • Multipart/form-data request inference

  • Problem details for error status codes

Action return types

  • Specific type

[HttpGet]
public List<Product> Get() =>
    _repository.GetProducts();
    
[HttpGet("syncsale")]
public IEnumerable<Product> GetOnSaleProducts() {
    var products = _repository.GetProducts();
    foreach (var product in products) {
        if (product.IsOnSale)
            yield return product;
    }
}

[HttpGet("asyncsale")]
public async IAsyncEnumerable<Product> GetOnSaleProductsAsync() {
    var products = _repository.GetProductsAsync();
    await foreach (var product in products) {
        if (product.IsOnSale)
            yield return product;
    }
}

The ActionResult types represent various HTTP status codes.

  • IActionResult type

Synchronous action

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Product))]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetById(int id) {
    if (!_repository.TryGetProduct(id, out var product))
        return NotFound();

    return Ok(product);
}

Asynchronous action

[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateAsync(Product product)
{
    if (product.Description.Contains("XYZ Widget"))
    {
        return BadRequest();
    }

    await _repository.AddProductAsync(product);

    return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
  • ActionResult<T> type

ActionResult<T> return type enables you to return a type deriving from ActionResult or return a specific type.

Synchronous action

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById(int id) {
    if (!_repository.TryGetProduct(id, out var product))
        return NotFound();

    return product;
}

Asynchronous action

[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Product>> CreateAsync(Product product) {
    if (product.Description.Contains("XYZ Widget"))
        return BadRequest();

    await _repository.AddProductAsync(product);

    return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}

[ProducesResponseType] indicates the known types and HTTP status codes to be returned by the action. This attribute produces more descriptive response details from web API help pages generated by tools like Swagger.

Last updated