Implementation
You will be writing action methods in each of your API
controllers to handle any of the HTTP request verbs that are
important for your application.
Controller
An API controller should inherit from ControllerBase and have the [ApiController]
attribute.
Controller Methods
There will be one method for each HTTP verb. You can write the
method using an ActionMethod
or IActionMethod
return type, but just return a POCO object and MVC will figure
out the correct format for the returned data--including the HTTP
status code. In addition, you can explicitly declare the status
code.
Each action method should have the route annotation below so
that the method names don't need to be included in the URL
[Route("api/[controller]")]
URL will be: http://localhost:5000/api/Book/
Status Codes
Each of the methods returns an IActionResult which allows the use
of StatusCode
helper methods. HTTP Status codes, along with the available
status code helper methods are shown below:
- 200: Ok
- 204: NoContent
- 400: BadRequest
- 401: Unauthorized
- 404: NotFound
- 409: Conflict
- 415: UnsupportedMediaType
- 422: UnprocessableEntity
- 500: InternalServerError
Examples
HTTP requests and a controller methods are shown below
for different HTTP request methods (verbs).
- GET
Use this to get all items or a specified item.
- URL to get all book items:
http://localhost:5000/api/Book
(See the code
below.)
- URL to get
a book item by ID:
http://localhost:5000/api/Book/3
(No code shown for this.)
[HttpGet]
public IActionResult GetBooks() {
var books = bookRepo.GetAllBooks();
if (books.Count == 0) {
return NotFound();
}
else {
return Ok(books);
}
}
- POST
Use
this to add an item.
- URL:
http://localhost:5000/api/Book
- Header:
content-type:application/json
- Body:
{
"title": "Tom Sawyer",
"date": "1/1/1876",
"author": "Mark Twain",
"birthdate": "11/30/1835"
}
[HttpPost]
public IActionResult AddBook(string title, string date,
string author, string birthdate) {
Book book = new Book { Title = title,
Date = DateTime.Parse(date) };
if (author != null) {
book.Authors.Add(new Author { Name = author, Birthday =
DateTime.Parse(birthdate)});
bookRepo.AddBook(book);
return
Ok(book);
}
else {
return
BadRequest();
}
}
Note: The method above receives parameters that
have been parsed from the POST request body.
Alternatively, the controller action method could use the [FromBody]
model binding behavior attribute which tells MVC
to bind data from the request body to an object of
the specified type--see Appel (2018).
- PUT
Use this to
replace an item specified by an ID, or create a new
item with this ID if the specified ID does not exist.
- URL
http://localhost:5000/api/Book/5
- Header:
content-type:application/json
- Body:
{
"title": "Oliver Twist",
"date": "3/1/1839",
"name": "Charles Dickens",
"birthday": "6/8/1870"
}
[HttpPut("{id} ")]
public IActionResult Replace(int id, string title,
string date, string author, string birthdate) {
Book book = new Book { Title = title,
Date = DateTime.Parse(date) };
book.BookID = id;
if (author != null) {
book.Authors.Add(new Author { Name = author, Birthday =
DateTime.Parse(birthdate) });
bookRepo.Edit(book);
return
Ok(book);
}
else {
return
BadRequest(); //
}
}
- PATCH
Use
this to update an item by changing a single field.
- URL
http://localhost:5000/api/Book/5
- Request header:
Content-Type:application/json
- Request body:
{
"op": "replace",
"path": "title",
"value": "David Copperfield"
}
[HttpPatch("{id} ")] //
TODO: Add support for more ops: remove, copy, move, test
public IActionResult UpdateBook(int id, string op,
string path, string value) {
Book book = bookRepo.GetBookById(id);
switch(path) {
case "title
":
book.Title =
value;
break;
case "date ":
book.Date = Convert.ToDateTime(value);
break;
case "author
":
book.Authors[0].Name = value; // TODO:
manage author collection
break;
case
"birthdate ":
book.Authors[0].Birthday = Convert.ToDateTime(value);
break;
default:
return BadRequest();
}
bookRepo.Edit(book);
return Ok(book);
}
- DELETE
Use this to delete
an
item by its
ID.
- URL
http://localhost:5000/api/Book/5
[HttpDelete("{id} ")]
public IActionResult DeleteBook(int id) {
Book book = bookRepo.GetBookById(id);
if (book != null) {
bookRepo.Delete(id);
return Ok();
}
else {
return
NotFound();
}
}
Notes
- In ASP.NET Core version 2.0, use of the [ApiController]
annotation was deprecated, but in 2.1 and later it is again
required on a controller class that will provide API
endpoints.
- Your controller can be a subclass of Controller, but it is
better to make it a subclass of ControllerBase (Controller
is a sub-class of ControllerBase) since Controller contains
View related members that you don't need.
Testing
One way to test a web API is to use a tool like Postman. This will let you write an HTTP
request, send it to an API endpoint, and view the response.
You can save the request for use again later.
Steps to create a request in Postman:
- Click + to create a new request tab.
- Select a request method (verb) from the drop-down list;
for example:
POST
- Enter the URL of the web API; for example:
http://localhost:5000/api/Book
- Select Headers and enter the header. If your request has a
JSON body, then enter:
Content-Type:application/json
- Select Body and
enter the request body; for example:
{
"title": "Tom Sawyer",
"date": "1/1/1876",
"author": "Mark Twain",
"birthdate": "11/30/1835"
}
Examples
- Source code on GitHub: ProfBird/BookInfo-Core-2-WebAPI
- Web service running online: BookInfo Service
References
- Freeman, Adam. (2017). Ch. 20, "Web API, " in Pro ASP.NET Core MVC 2.
- Appel, Rachel. (2019). "Model Binding in ASP.NET Core",
in ASP.NET
Core Documentation. Microsoft.
- Anderson, Rick & Wasson Mike. (2019). "Tutorial: Create a web API with ASP.NET
Core MVC," in ASP.NET
Core Documentation. Microsoft.
- Addie, Scott. (2020). "Controller action return types in
ASP.NET Core Web API," in ASP.NET
Core Documentation. Microsoft.
- "StatusCodeResult Class," in ASP.NET
Core Documentation. Microsoft.
- Crockford, Douglas. (2018). "Introducing JSON" in How JavaScript Works.
- Spasojevic, Marinko. (2021). "Using
HttpClient to Send HTTP PATCH Requests in ASP.NET Core".
Code-Maze.
This article has a good explanation of the HTTP PATCH
request.