# GET

GET reads data. One \[HttpGet\] action returns the whole collection, and an \[HttpGet("{id}")\] action returns one item, its id taken from the address. ASP.NET Core sends what they return as JSON, with 200 OK.

Journeyman · ASP.NET Core · REST API · Updated November 3, 2026

## After this lesson you can

- Write GET actions that return a list, and one item by its id, as JSON

## Key takeaways

- `[HttpGet]` answers the controller's own route, and `[HttpGet("{id}")]` adds to it, so `GET /api/categories/8` fills `int id` with 8.
- Return a `List<Category>` and the client gets a JSON array; return one `Category` and it gets one JSON object, both with `200 OK`.
- A parameter that isn't in the route, such as `string? search`, comes from the query string: `?search=pro`.
- `/api/categories/abc` answers `400` because `abc` can't become an `int`; with `{id:int}` in the template, it answers `404` instead.
- When `GetById` returns `null` for a missing category, the client gets `204 No Content`, not the `404 Not Found` it should get.

A client **reads** data with a `GET` request. It sends no body: the address says everything.

## The whole collection

```csharp
[HttpGet]
public List<Category> GetAll()
{
    return categoryDao.GetAll();
}
```

`[HttpGet]` with no template answers the controller's own route, `GET /api/categories`. The DAO's query is the one you'd expect:

```csharp
public List<Category> GetAll()
{
    using SqlConnection connection = new SqlConnection(connectionString);
    return connection.Query<Category>(
        "SELECT CategoryId, CategoryName, Description FROM Categories ORDER BY CategoryId;").ToList();
}
```

```http
GET {{HostAddress}}/api/categories
```

```http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[
  {
    "categoryId": 1,
    "categoryName": "Beverages",
    "description": "Soft drinks, coffees, teas, beers, and ales"
  },
  {
    "categoryId": 2,
    "categoryName": "Condiments",
    "description": "Sweet and savory sauces, relishes, spreads, and seasonings"
  },
  ...
]
```

A `List<Category>` becomes a JSON **array**, `[ ... ]`, of objects. You returned a list; ASP.NET Core did the rest.

## One item by its id

```csharp
[HttpGet("{id}")]
public Category? GetById(int id)
{
    return categoryDao.GetById(id);
}
```

The template `"{id}"` is added to the controller's route, so this action answers `GET /api/categories/8`, and the `int id` parameter gets the `8`. The DAO uses `QuerySingleOrDefault`, which returns `null` when there's no such row:

```csharp
public Category? GetById(int categoryId)
{
    using SqlConnection connection = new SqlConnection(connectionString);
    return connection.QuerySingleOrDefault<Category>(
        "SELECT CategoryId, CategoryName, Description FROM Categories WHERE CategoryId = @CategoryId;",
        new { CategoryId = categoryId });
}
```

```http
GET {{HostAddress}}/api/categories/8
```

```http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "categoryId": 8,
  "categoryName": "Seafood",
  "description": "Seaweed and fish"
}
```

One object becomes one JSON object, `{ ... }`.

Two things to notice:

- **`/api/categories/abc`** answers `400 Bad Request` on its own: `abc` can't become an `int`, and `[ApiController]` reports it. To be stricter, write `"{id:int}"`: then `abc` doesn't match the route at all, and answers `404`.
- **`/api/categories/300`** answers `204 No Content`, as *HTTP Status Codes: an overview* warned: the DAO returned `null`. *Returning ActionResult&lt;T>* fixes it to a proper `404`.

## Filtering with the query string

A GET can take optional extras from the query string, exactly as MVC actions did. A parameter that isn't in the route is looked for there:

```csharp
[HttpGet]
public List<Category> GetAll(string? search)
{
    List<Category> categories = categoryDao.GetAll();
    if (search != null)
    {
        categories = categories.Where(c => c.CategoryName.Contains(search, StringComparison.OrdinalIgnoreCase)).ToList();
    }
    return categories;
}
```

`GET /api/categories?search=pro` returns *Dairy Products* and *Produce*; `GET /api/categories` still returns everything. (For a big table, the DAO would filter in SQL instead, with a `WHERE ... LIKE`.)

## Check yourself

1 question to try on the lesson page.

## So what

A GET action is a DAO call and a `return`. The route says which item, the query string says how to filter, and ASP.NET Core turns whatever you return into JSON.

## Key terms

- [GET](https://www.ask-codey.com/glossary/get)
- Route Template
- Route Parameter

## Cheat sheets

- [GET](https://www.ask-codey.com/cheat-sheets/web-apis-with-controllers-get-cheat-sheet)

Source: https://www.ask-codey.com/lessons/web-apis-with-controllers-get
