Rest Apis

By the end of this lesson you'll be able to design a REST API the way professionals do — modelling resources , mapping each HTTP verb to the right action, returning correct status codes , shaping data with DTOs , and choosing between minimal APIs and controllers . You'll practise the underlying logic in the runner, then read production-ready ASP.NET Core worked examples.

Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.

Part of the free C# course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

A REST API is like a restaurant menu of resources . The menu lists the things you can ask for — dishes, drinks, the bill — and these are your resources ( /api/orders , /api/products ). The HTTP verbs are the actions you take with each one: GET reads the menu (show me the dishes), POST places an order (create something new), PUT changes your order, and DELETE cancels it. The kitchen always replies with a status code — "here you go" (200), "your order is in" (201), "we don't have that" (404). You never walk into the kitchen and grab a pan yourself; you go through the waiter (the API), and the menu is the same for every customer (a uniform interface).

1. What "REST" Actually Means

REST (Representational State Transfer) is a set of conventions for building web APIs around resources — the nouns your system is about, like products, orders, or users. Each resource gets a URL ( /api/products/1 ), and you act on it with the standard HTTP verbs instead of inventing your own. Two ideas matter most. First, statelessness : every request carries everything the server needs, so the server doesn't remember you between calls — that's what lets an API scale to thousands of servers. Second, a uniform interface : GET always reads and never changes data, POST always creates, and so on, so any developer can guess how your API behaves. Get the nouns and verbs right and the rest of the design follows.

2. Resources, Verbs & Status Codes (Worked Example)

Here's a complete minimal API exposing a /api/todos resource. Read each endpoint and the comment beside it — that comment is the HTTP response the call returns. Notice how each verb maps to one action and one success status code, and how a missing resource always returns 404 Not Found . This is the whole CRUD shape in one file.

A minimal API for a Todo resource. The comments show the exact HTTP response for each call.

This needs a web server, so it won't run in the browser runner — but you'll model its logic in the runnable exercise just below.

Now you try the logic behind it in plain C# — exactly what each endpoint decides before it sends a response. Fill in the ___ blanks, then run it.

3. Minimal APIs vs Controllers

ASP.NET Core gives you two styles. Minimal APIs (the example above) define endpoints with a line each — app.MapGet(...) , app.MapPost(...) — with almost no ceremony, which is perfect for microservices and small services. Controllers group related endpoints into a class decorated with attributes like [HttpGet] and [Route] ; they scale better for large APIs because they centralise routing, model binding, filters, and validation. They're equally "REST" — the difference is organisation, not behaviour. Reach for minimal APIs when an app is small or focused, and controllers when it grows many endpoints that share cross-cutting concerns.

The same kind of API as a controller — with model binding, DTOs, and versioning in the route.

Read the / attributes — that's model binding, covered next.

4. Model Binding & DTOs

Model binding is ASP.NET Core reading values out of the incoming request and handing them to your method as typed parameters. {' '} in the route binds to an int id parameter; [FromQuery] reads the query string ( ?minPrice=100 ); [FromBody] deserialises the JSON request body into an object. A DTO (Data Transfer Object) is the dedicated shape for that data — one DTO for what the client may send ( CreateProductDto ) and one for what you send back ( ProductDto ). DTOs matter because your internal entity might have fields you must never expose (a password hash, an internal cost) or never let the client set (the Id , an IsAdmin flag). Records make DTOs a one-liner. Practise building one now.

Once real clients depend on your API, you can't freely change its shape — renaming a field or removing one breaks them. Versioning lets you ship breaking changes under a new version while old clients keep using the old one. The simplest, most common approach is to put the version in the URL path:

Add /v1/ from day one — it's far easier than retrofitting it later. Other strategies include a header ( api-version: 2 ) or a query string ( ?api-version=2 ); the official Asp.Versioning package supports all three. Whichever you pick, the rule is the same: never silently break an existing version.

Q: What's the difference between PUT and POST?

POST creates a new resource and the server assigns its id ( 201 Created ). PUT replaces an existing resource at a known URL ( 200 OK , or 404 if it doesn't exist). Rule of thumb: POST to a collection ( /api/todos ), PUT to a specific item ( /api/todos/1 ).

Both are first-class and equally RESTful. Use minimal APIs for small or focused services where less ceremony wins; use controllers when an API grows many endpoints that share routing, filters, and validation. You can even mix them in one project.

Q: Why bother with a DTO instead of returning my entity?

A DTO is your public contract. Returning the entity ties your API to your database and risks leaking fields you never meant to expose. A DTO lets you change storage freely and control exactly what goes over the wire.

400 Bad Request means the client sent something invalid (a missing field, a bad value). 404 Not Found means the request was fine but the resource doesn't exist (no product with that id). Validation failures are 400; missing ids are 404.

The server keeps no memory of you between requests — each call carries everything it needs (such as an auth token). That's what lets you put many identical servers behind a load balancer, because any of them can handle any request.

No blanks this time — just a brief and an outline. Model an in-memory /api/notes resource over a List<Note> , with Get , Post , and Delete methods that return the same status strings a real REST API would. This is the runner-friendly version of everything you read in the worked examples. Run it and check your output against the comments.

Practice quiz

Which HTTP verb is used to CREATE a new resource?

  • GET
  • PUT
  • POST
  • DELETE

Answer: POST. POST creates a new resource; GET reads, PUT updates/replaces, DELETE removes.

What status code should a successful POST that creates a resource return?

  • 201 Created
  • 200 OK
  • 204 No Content
  • 404 Not Found

Answer: 201 Created. A successful create returns 201 Created, ideally with a Location header to the new resource.

What status code is appropriate for a successful DELETE with nothing to send back?

  • 200 OK
  • 201 Created
  • 400 Bad Request
  • 204 No Content

Answer: 204 No Content. 204 No Content signals success with no body, the typical response for a DELETE.

When should an API return 404 Not Found?

  • When input validation fails
  • When the requested resource id doesn't exist
  • When the server crashes
  • On every successful GET

Answer: When the requested resource id doesn't exist. 404 means the request was fine but the resource doesn't exist; invalid input is 400 instead.

What does 'stateless' mean for a REST API?

  • The server keeps no memory of the client between requests
  • The server stores no data
  • Requests must use GET only
  • Responses are never cached

Answer: The server keeps no memory of the client between requests. Each request carries everything the server needs, so any server behind a load balancer can handle it.

Why should an API return a DTO instead of the database entity?

  • DTOs are faster to serialise
  • Entities can't be serialised
  • To control the public shape and avoid leaking internal fields
  • DTOs are required by HTTP

Answer: To control the public shape and avoid leaking internal fields. A DTO is the public contract; returning the entity ties the API to storage and can leak sensitive fields.

What is model binding in ASP.NET Core?

  • Mapping database tables to classes
  • Reading values from the incoming request into typed method parameters
  • Validating the database schema
  • Caching responses

Answer: Reading values from the incoming request into typed method parameters. Model binding pulls route, query, and body values out of the request and hands them to your method as typed parameters.

What is the difference between PUT and POST?

  • They are identical
  • PUT creates and POST deletes
  • POST is read-only
  • POST creates a new resource; PUT replaces an existing one at a known URL

Answer: POST creates a new resource; PUT replaces an existing one at a known URL. POST creates (server assigns the id, 201); PUT replaces an existing resource at a known URL (200 or 404).

What is 'over-posting' (mass assignment) and how do you prevent it?

  • Sending too many requests; add rate limiting
  • Binding the request straight onto your entity, letting clients set fields they shouldn't; bind to a narrow input DTO
  • Posting to the wrong URL; fix the route
  • Returning too much data; paginate

Answer: Binding the request straight onto your entity, letting clients set fields they shouldn't; bind to a narrow input DTO. Binding directly to the entity lets a client set fields like Id or IsAdmin; bind to a narrow input DTO instead.

A GET request, by REST convention, must never do what?

  • Return JSON
  • Use a status code
  • Change data on the server
  • Have a URL

Answer: Change data on the server. GET must be safe and read-only; caches and crawlers assume a GET never changes state.