# Controller-based APIs

### ApiController attribute <a href="#apicontroller-attribute" id="apicontroller-attribute"></a>

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.

<table><thead><tr><th width="206">Attribute</th><th>Binding source</th></tr></thead><tbody><tr><td><code>[FromBody]</code></td><td>Request body</td></tr><tr><td><code>[FromForm]</code></td><td>Form data in the request body</td></tr><tr><td><code>[FromHeader]</code></td><td>Request header</td></tr><tr><td><code>[FromQuery]</code></td><td>Request query string parameter</td></tr><tr><td><code>[FromRoute]</code></td><td>Route data from the current request</td></tr><tr><td><code>[FromServices]</code></td><td>The request service injected as an action parameter</td></tr></tbody></table>

* Multipart/form-data request inference
* Problem details for error status codes

### Action return types

* Specific type

```csharp
[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;
    }
}
```

{% hint style="info" %}
The `ActionResult` types represent various HTTP status codes.
{% endhint %}

* `IActionResult` type

#### Synchronous action <a href="#synchronous-action" id="synchronous-action"></a>

```csharp
[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 <a href="#asynchronous-action" id="asynchronous-action"></a>

```csharp
[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.&#x20;

#### Synchronous action <a href="#synchronous-action-1" id="synchronous-action-1"></a>

```csharp
[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 <a href="#asynchronous-action-1" id="asynchronous-action-1"></a>

```csharp
[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.
