Build By Example
Here is a simple Web API of a Todo App using Quickie.
Step 1: Create a new Web API Project
dotnet new webapi -n todo.apis --use-controllers
Step 2: Install Quickie
Install Quickie from NuGet:
dotnet add package Quickie
Step 3: Configure Quickie in Program.cs
In your Program.cs
, configure Quickie as follows:
builder.Services.QuickieConfig(options => {
options.ShowCustomErrorMessage = true;
options.RateLimitingConfiguration = new RateLimitConfiguration
{
DisableRateLimiting = false
};
options.IdempotencyConfiguration = new IdempotentConfiguration
{
Enable = true
};
});
app.AddQuickie();
Explanation:
- For this project, we are enabling Idempotency.
- Rate limiting is enabled by default, but we chose to explicitly configure it here.
- Custom error messages are shown when exceptions occur.
Step 4: Create a Dto and Entity
public record TodoDto(int Id, string Title, string Description) : CrudDto;
public class TodoEntity : CrudEntity
{
[Key]
public int Id { get; set; }
public required string Title { get; set; }
public required string Description { get; set; }
public required DateTime CreatedDate { get; set; }
}
Step 5: Create a Controller
For our Todo app, we need CRUD operations:
- C -> Create Todo
- R -> Read Todo
- U -> Update Todo
- D -> Delete Todo
Here is the TodoController
:
public class TodoController(ITodoService requestHandler) : CrudController<TodoDto, ITodoService, int>(requestHandler);
Step 6: Request handler (Service layer) Setup
Todo Service
public interface ITodoService : ICrudRequestHandler<TodoDto, int>;
public class TodoService(ICrudDataHandler<TodoEntity, int> dataHandler) : CrudRequestHandler<TodoDto, TodoEntity, ITodoRepo, int>(dataHandler), ITodoService
{
protected override TodoEntity MapToEntity(TodoDto request)
{
var d = new TodoEntity()
{
Id = request.Id,
Title = request?.Title,
Description = request?.Description,
CreatedDate = DateTime.Now
};
return d;
}
protected override TodoDto MapToDto(TodoEntity request)
{
var d = request is not null ? new TodoDto(request.Id, request?.Title + " id:" + request?.Id, request?.Description) : default;
return d;
}
}
Note: Mapping must be done manually. You can use any mapping library or write your own logic.
Todo Repository (Data handler)
public interface ITodoRepo : ICrudDataHandler<TodoEntity, int>;
public class TodoRepo(ApplicationDbContext dbContext) : CrudDataHandler<TodoEntity, ApplicationDbContext, int>(dbContext), ITodoRepo;
Step 7: Configure Database Context
public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : DbContext(options)
{
public DbSet<TodoEntity> TodoEntity { get; set; }
}
Step 8: Register Services in DI
Register the services in Program.cs
:
builder.Services.AddScoped<ITodoService, TodoService>();
builder.Services.AddScoped<ITodoRepo, TodoRepo>();
builder.Services.AddScoped<ICrudDataHandler<TodoEntity, int>, TodoRepo>();
Step 9: Making Requests with Idempotency
Since Idempotency is enabled, you must provide an X-Idempotency-Key
with each request (POST calls). For duplicate requests, the API will respond with a 409 Conflict status.
Example Request:
curl -X 'POST' \
'http://localhost:5162/api/Todo' \
-H 'accept: application/json' \
-H 'X-Idempotency-Key: c311bef0-9953-45b1-bb73-70169e1a3de5' \
-H 'Content-Type: application/json' \
-d '{
"id": 0,
"title": "work",
"description": "feature 0"
}'
Not Just CRUD
Quickie is versatile and supports scenarios beyond CRUD operations:
- CRUD for Collection: Bulk create, read, update, and delete operations are supported, making it easy to handle multiple entities in a single request.
- Readonly: For entities where only read operations are required.
- Write-only: For scenarios where entities can only be written to, but not read.
- Edit-only: For entities that support updates but not creation or deletion.
- Readonly Collections: You can define collections where only bulk read operations are required, and no modifications are allowed.
You can choose the appropriate functionality based on your application's needs.
API is Ready!
That's it! Your fully functional Web API with:
- CRUD functionality
- Built-in Idempotency (to prevent duplicate requests)
- Built-in Rate Limiting (enabled by default)
Things to Consider
- DTOs should be record types.
- Entities are class (reference types).