Building RESTful APIs with ASP.NET Core

This tutorial guides you through the process of creating and consuming RESTful APIs using ASP.NET Core. We'll cover essential concepts like routing, controllers, model binding, data formatting, and basic security.

1. Project Setup

First, create a new ASP.NET Core Web API project. Open your terminal or command prompt and run:

dotnet new webapi -o MyAwesomeApi
cd MyAwesomeApi

This command creates a new directory named MyAwesomeApi containing a basic Web API project structure.

2. Understanding Controllers

Controllers are classes that handle incoming HTTP requests and return HTTP responses. The default template includes a WeatherForecastController. Let's create our own simple API for managing a list of items.

Creating an Item Model

Define a simple class to represent our item:

// Models/Item.cs
namespace MyAwesomeApi.Models
{
    public class Item
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
    }
}

Creating an Items Controller

Create a new controller file, for example, Controllers/ItemsController.cs:

// Controllers/ItemsController.cs
using Microsoft.AspNetCore.Mvc;
using MyAwesomeApi.Models;
using System.Collections.Generic;
using System.Linq;

namespace MyAwesomeApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ItemsController : ControllerBase
    {
        private static List<Item> _items = new List<Item>
        {
            new Item { Id = 1, Name = "Laptop", Description = "A portable computer." },
            new Item { Id = 2, Name = "Keyboard", Description = "An input device." }
        };

        // GET: api/Items
        [HttpGet]
        public ActionResult<IEnumerable<Item>> Get()
        {
            return Ok(_items);
        }

        // GET: api/Items/5
        [HttpGet("{id}")]
        public ActionResult<Item> Get(int id)
        {
            var item = _items.FirstOrDefault(i => i.Id == id);
            if (item == null)
            {
                return NotFound();
            }
            return Ok(item);
        }

        // POST: api/Items
        [HttpPost]
        public ActionResult<Item> Post([FromBody] Item newItem)
        {
            if (newItem == null)
            {
                return BadRequest();
            }
            newItem.Id = _items.Any() ? _items.Max(i => i.Id) + 1 : 1;
            _items.Add(newItem);
            return CreatedAtAction(nameof(Get), new { id = newItem.Id }, newItem);
        }

        // PUT: api/Items/5
        [HttpPut("{id}")]
        public IActionResult Put(int id, [FromBody] Item updatedItem)
        {
            if (updatedItem == null || updatedItem.Id != id)
            {
                return BadRequest();
            }

            var existingItem = _items.FirstOrDefault(i => i.Id == id);
            if (existingItem == null)
            {
                return NotFound();
            }

            existingItem.Name = updatedItem.Name;
            existingItem.Description = updatedItem.Description;

            return NoContent();
        }

        // DELETE: api/Items/5
        [HttpDelete("{id}")]
        public IActionResult Delete(int id)
        {
            var item = _items.FirstOrDefault(i => i.Id == id);
            if (item == null)
            {
                return NotFound();
            }

            _items.Remove(item);
            return NoContent();
        }
    }
}

3. Running the API

You can run your API project using the .NET CLI:

dotnet run

By default, the API will be hosted on https://localhost:5001 and http://localhost:5000. ASP.NET Core's default template includes Swagger/OpenAPI support, which provides a UI to interact with your API. Navigate to https://localhost:5001/swagger in your browser to explore your endpoints.

4. Key Concepts Explained

  • [Route("api/[controller]")]: This attribute defines the base route for the controller. [controller] is a placeholder that gets replaced by the controller's name (e.g., Items).
  • [ApiController]: This attribute enables several API-specific behaviors, such as automatic model validation and attribute routing.
  • [HttpGet], [HttpPost], [HttpPut], [HttpDelete]: These attributes map controller actions to specific HTTP methods.
  • [HttpGet("{id}")]: This defines a route that includes a parameter, like /api/Items/1.
  • ActionResult<T>: This return type allows you to return either a specific type (e.g., Item) or an IActionResult (e.g., NotFound(), Ok()).
  • Ok(): Returns an HTTP 200 OK response.
  • NotFound(): Returns an HTTP 404 Not Found response.
  • BadRequest(): Returns an HTTP 400 Bad Request response.
  • NoContent(): Returns an HTTP 204 No Content response, typically used for successful PUT and DELETE operations.
  • Created(uri, value): Returns an HTTP 201 Created response with a location header pointing to the created resource.
  • [FromBody]: Indicates that a parameter should be deserialized from the request body.

5. Further Exploration

This tutorial covers the basics. To build robust APIs, consider exploring: