C Sharp - API Topics

My API’s are usually exposed using what I call controlling classes. These classes define different API methods.

Sample class

Here’s an example of a controlling class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
using Microsoft.AspNetCore.Mvc;
using Checkbook.API.Base;
namespace Checkbook.API.Reconcile
{
// test with http://localhost:xxx/api/v1/reconciles
[Route("api/v1/[controller]")]
[ApiController]
public class ReconcilesController : BaseController
{
private readonly IReconcileService _reconcileService;

public ReconcilesController(IReconcileService reconcileService)
{
_reconcileService = reconcileService;
}

[HttpGet]
public async Task<IActionResult> GetAll()
{
IResult<List<ReconcileViewModel>> result = await _reconcileService.GetAllReconcilesAsync();
return Ok(result);
}

[HttpGet("{id}")]
public async Task<IActionResult> GetOne(long id)
{
var result = await _reconcileService.GetReconcileById(id);
return Ok(result);
}

[HttpGet("{bankAccountId}/{startDate}")]
public async Task<IActionResult> GetByBankAccountNdStartDate(long bankAccountId, DateOnly startDate)
{
var result = await _reconcileService.GetByBankAccountNdStartDate(bankAccountId, startDate);
return ReturnResult(result);
}

[HttpPost]
public async Task<IActionResult> Add(
[FromBody] IEnumerable<ReconcileViewModel> reconcileVm)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);

var result = await _reconcileService.AddReconcile(reconcileVm);
return Ok(result);
}

[HttpPut]
public async Task<IActionResult> Update([FromBody] ReconcileViewModel reconcileVm)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
//return ReturnResult(_reconcileService.UpdateReconcile(reconcileVm));

var result = await _reconcileService.UpdateReconcile(reconcileVm);
return Ok(result);
}

[HttpDelete("{id}")]
public async Task<IActionResult> Delete(long id)
{
var result = await _reconcileService.DeleteReconcile(id);
return Ok(result);
}
}
}
````csharp

Here are a few interesting commands

````csharp
// test with http://localhost:xxx/api/v1/reconciles
[Route("api/v1/[controller]")]
[ApiController]
public class ReconcilesController : BaseController
{

The Route and ApiContrller statements are called Annotation’s. You add Annotations to classes, or methods as a way to add functionality to your code without adding the code itself.

Route defines the URL path to access methods in the class.

ApiController is used to tell the compiler that the class is an API controller. When you use the ApiController attribute, you are required to add the word Controller to the class name as a suffix.

‘public class ReconcilesController’ is the class name. The methods in this class can be reached with something like http://localhost:5000/api/v1/reconciles

1
2
3
4
5
6
private readonly IReconcileService _reconcileService;

public ReconcilesController(IReconcileService reconcileService)
{
_reconcileService = reconcileService;
}

Public ReconcilesController(…) is executed each time the class is instantiated. When the class is instantiated, a property called Dependency Injection will inject (IReconcileService reconcileService) a class which was created that implements the IReconcileService interface.

We store a reference of the class being passed in into the private variable _reconcileService.

1
2
3
4
5
6
[HttpGet]
public async Task<IActionResult> GetAll()
{
IResult<List<ReconcileViewModel>> result = await _reconcileService.GetAllReconcilesAsync();
return Ok(result);
}

This method returns records from the database. It does this by calling the GetAllReconcilesAsync() method in the class that implements the IReconcileService interface. it returns a List object loaded with ReconcileViewModel objects. This is wrapped in a IResult object..

[HttpGet] is an annotation that tells the compiler that the method is a method that can be called via an HTTP GET request.

There’s a few other method related annotations [HttpPost], [HttpPut], [HttpDelete]. These are used to tell the compiler that the method is a method that can be called via an HTTP POST, PUT, or DELETE request. This is somewhat of a tricky concept, but it’s important to understand. Suffice to say browsers can send HTTP GET, POST, PUT, and DELETE requests to API’s. Programs like Postman can also send HTTP GET, POST, PUT, and DELETE requests to API’s.

1
2
[HttpGet("{id}")]
public async Task<IActionResult> GetOne(long id)

You can configure the Get (post, put, and delete statements) so that they accept multiple parameters. In this particular example, the method GetOne() accepts a single parameter called id. The id parameter is a long data type. The id parameter is passed in as a parameter to the method. The id parameter is used to retrieve a record from the database.

You could enter a command like this in a browser: http://localhost:5000/api/v1/reconciles/1 and it will return a record from the database.

To pass 2 properties to a method, you can use the following syntax:

1
2
[HttpGet("{bankAccountId}/{startDate}")]
public async Task<IActionResult> GetByBankAccountNdStartDate(long bankAccountId, DateOnly startDate)

In this case 2 arguments are expected. They are pulled out of the URL and passed to the GetByBankAccountNdStartDate() method. The first argument going into the bankAccountId parameter and the second argument going into the startDate parameter.

Swagger

Open API is a specification for describing, producing, consuming, and visualizing RESTful web services. Years ago Open API was called Swagger. Maybe Swagger started getting popular and renamed part of it’s technologies to Open API.

Swagger is a tool that helps you document your API’s.

You would add different different stuff to your methods to document your API’s.

Here’s an example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <summary>
/// Returns a ReconcileViewModel object (specifically the one with the ID provided)
/// </summary>
/// <param name="id">
/// This is the ID of the Reconcile record you are looking for.
/// Maps to Reconiles.Id </param>
/// <returns></returns>
[SwaggerResponse(
StatusCodes.Status200OK,
"HTTP 200 means a model is being returned. Check the WasSuccessfulTrue to determine if it worked properly",
typeof(IResult<ReconcileViewModel>))]
[SwaggerResponseExample(
StatusCodes.Status200OK,
typeof(ReconcilesControllerSwashbuckleExamples.ReconcileGetOneExample))]
[SwaggerResponseExample(
StatusCodes.Status200OK,
typeof(ReconcilesControllerSwashbuckleExamples.ReconcileGetAll))]
[HttpGet("{id}")]
public async Task<IActionResult> GetOne(long id)
{
var result = await _reconcileService.GetReconcileById(id);
return Ok(result);
}

You’ll notice a mix of comments (that start with ///) and Annotations. The compiler will call a function to read through the code and generate documentation. In this case the documentation that is generated will give you a summary and a description of the ID parameter. There is also comments that describe what is returned.

More information about Swagger can be found here:

  • Swashbuckle There are articles in this section that describe different aspects of Swashbuckle.

More information about API can be found here: