Russkyc.MinimalApi.Framework
0.8.0
Prefix Reserved
See the version list below for details.
dotnet add package Russkyc.MinimalApi.Framework --version 0.8.0
NuGet\Install-Package Russkyc.MinimalApi.Framework -Version 0.8.0
<PackageReference Include="Russkyc.MinimalApi.Framework" Version="0.8.0" />
paket add Russkyc.MinimalApi.Framework --version 0.8.0
#r "nuget: Russkyc.MinimalApi.Framework, 0.8.0"
// Install Russkyc.MinimalApi.Framework as a Cake Addin #addin nuget:?package=Russkyc.MinimalApi.Framework&version=0.8.0 // Install Russkyc.MinimalApi.Framework as a Cake Tool #tool nuget:?package=Russkyc.MinimalApi.Framework&version=0.8.0
Russkyc.MinimalApi.Framework - A Generic API Crud Generator for EntityFrameworkCore
Dynamically generates a generic CRUD API implementation backed with Entity Framework Core and Minimal API. This can be used to create a quick backend for prototyping apps that use CRUD operations.
✨ What's New:
Migrations support (using custom DbContext implementation) learn more...
Potential use-cases
- Quick API prototyping
- Small projects that only require CRUD functionality
- Frontend Testing (if a backend API is needed)
Getting Started
Installation
To install the Russkyc.MinimalApi.Framework
package, you can use the NuGet Package Manager or the .NET CLI.
Using .NET CLI
Run the following command in your terminal:
dotnet add package Russkyc.MinimalApi.Framework
Setup
Follow these steps to set up the Russkyc.MinimalApi.Framework
in your project.
Create a new ASP.NET Core Web API project if you don't already have one.
Add the required services and API endpoint mappings in the
Program.cs
file:// Used by reflection to know where to find entity classes var assembly = Assembly.GetExecutingAssembly(); // 1. Entity Context Services // `options.UseInMemoryDatabase()` can be replaced with other EF Core Data Providers builder.Services.AddDbContextService(assembly, options => options.UseInMemoryDatabase("sample")); // 2. Map Entity CRUD Endpoints // `MapGroup()` is not required, used to add the "/api" prefix. // Can simply be `app.MapAllEntityEndpoints<int>(assembly);` app.MapGroup("api") .MapAllEntityEndpoints<int>(assembly);
This is how the full
Program.cs
might look likeusing System.Reflection; using Microsoft.EntityFrameworkCore; using Russkyc.MinimalApi.Framework; var builder = WebApplication.CreateBuilder(args); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var assembly = Assembly.GetExecutingAssembly(); // Add Entity Context Services builder.Services.AddAllEntityServices(assembly, options => options.UseInMemoryDatabase("sample")); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); // Map Entity CRUD Endpoints app.MapGroup("api") .MapAllEntityEndpoints<int>(assembly); app.Run();
Setting-up entity classes
All entity classes should inherit from the DbEntity<TKeyType> abstract class.
Where TKeyType
is the Id type of the entity.
SampleEntity Class
public class SampleEntity : DbEntity<int>
{
public string Property { get; set; }
public virtual SampleEmbeddedEntity EmbeddedEntity { get; set; }
}
SampleEmbeddedEntity Class
public class SampleEmbeddedEntity : DbEntity<int>
{
public string Property2 { get; set; }
}
You now have a fully working EntityFrameworkCore backed MinimalApi CRUD project.
Advanced Setup
Custom DbContext (Useful for migrations support)
To support database migrations, we can create a custom dbcontext class that inherits from BaseDbContext
using Microsoft.EntityFrameworkCore;
using Russkyc.MinimalApi.Framework;
namespace SampleProject;
public class CustomDbContext : BaseDbContext
{
public CustomDbContext(DbContextOptions options) : base(options)
{
}
// Entity collections are required to be defined
// using the naming convention `<ClassName>Collection`
public DbSet<SampleEmbeddedEntity> SampleEmbeddedEntityCollection { get; set; }
public DbSet<SampleEntity> SampleEntityCollection { get; set; }
}
Database Initialization
These are different database action types that can be defined in the AddAllEntityServices
or AddEntityServices
extensions using the databaseAction
parameter:
- None - Default Action
- DatabaseAction.EnsureCreated - Run
Database.EnsureCreated()
- DatabaseAction.DeleteAndCreate - Run
Database.EnsureDeleted()
beforeDatabase.EnsureCreated()
As an example:
builder.Services.AddAllEntityServices(assembly,
options => options.UseSqlite("Data Source=test.sqlite"),
databaseAction: DatabaseAction.DeleteAndCreate);
This ensures that a fresh database is used in every run. If you only need
to set the database once, DatabaseAction.EnsureCreated
is the recommended option
Advanced Route Options
You can modify the endpoint options using the routeOptionsAction
parameter. For example, to require authorization for
all endpoints:
app.MapGroup("api")
.MapAllEntityEndpoints<int>(assembly, routeOptions => routeOptions.RequireAuthorization());
Advanced Querying
Apart from the standard CRUD api functionality, there is also some support for advanced querying.
Entity Framework Core Navigation Properties
If you do a get requrest to the endpoint /api/sampleentity
you will
recieve a response that looks like this:
[
{
"id": 1,
"property": "Entity 1",
"embeddedEntity": null
},
{
"id": 2,
"property": "Entity 2",
"embeddedEntity": null
},
{
"id": 3,
"property": "Entity 3",
"embeddedEntity": null
},
{
"id": 4,
"property": "Entity 4",
"embeddedEntity": null
}
]
This is because navigation properties for referenced entities are not
automatically included (for performance purposes). you can use the include
query parameter to include the referenced entity when needed.
GET /api/sampleentity?include=embeddedentity
Then you will have this result:
[
{
"id": 1,
"property": "Entity 1",
"embeddedEntity": {
"id": 1,
"property2": "Embedded Entity 1"
}
},
{
"id": 2,
"property": "Entity 2",
"embeddedEntity": {
"id": 2,
"property2": "Embedded Entity 2"
}
},
{
"id": 3,
"property": "Entity 3",
"embeddedEntity": {
"id": 3,
"property2": "Embedded Entity 3"
}
},
{
"id": 4,
"property": "Entity 4",
"embeddedEntity": {
"id": 4,
"property2": "Embedded Entity 4"
}
}
]
Filter query support (with the help of DynamicExpressionParser in System.Linq.Dynamic.Core)
entities can now be filtered with the filter
queryParam and supports standard expressions. Parameters should be
prefixed with @
in order to be valid, eg; a parameter named Content
should be used as @Content
. Here are a few
examples:
GET /api/sampleentity?filter=@Content.StartsWith("hello")
GET /api/sampleentity?filter=@Content.StartsWith("hi") && !@Content.Contains("user")
GET /api/sampleentity?filter=@Count == 1 || @Count > 8
GET /api/sampleentity?filter=@ContactPerson != null
These are visualized for readability, in actual use, the filter value should be Url Encoded.
Pagination
By default pagination is disabled and the query collection response returns something like this
[
{
"id": 1,
"property": "Entity 1",
"embeddedEntity": {
"id": 1,
"property2": "Embedded Entity 1"
}
},
{
"id": 2,
"property": "Entity 2",
"embeddedEntity": {
"id": 2,
"property2": "Embedded Entity 2"
}
}
]
To enable pagination, set the paginate
query param to true
and set the page
, pageSize
query params as needed. as an example:
GET /api/sampleentity?paginate=true&page=1&pageSize=1
This will now return a PaginatedCollection
object with this json schema:
{
"data": [
{
"property": "Entity 1",
"embeddedEntity": null,
"id": "84e93f60-b2bc-4303-af0a-c51c205addb9"
}
],
"page": 1,
"pageSize": 1,
"totalRecords": 2,
"totalPages": 2
}
Batch Endpoints
Batch endpoints are supported for adding, updating, and deleting multiple entities at once.
Batch Insert
POST /api/sampleentity/batch
Content-Type: application/json
[
{
"id": 1,
"property": "Entity 1",
"embeddedEntity": null
},
{
"id": 2,
"property": "Entity 2",
"embeddedEntity": null
}
]
Batch Update
PUT /api/sampleentity/batch
Content-Type: application/json
[
{
"id": 1,
"property": "Updated Entity 1",
"embeddedEntity": null
},
{
"id": 2,
"property": "Updated Entity 2",
"embeddedEntity": null
}
]
Batch Update with Filters and Dynamic Fields
PATCH /api/sampleentity/batch?filter=@property.Contains("Old")
Content-Type: application/json
{
"property": "Updated Value"
}
Batch Delete
DELETE /api/sampleentity/batch?filter=@Count > 8
Important things to consider
- When using generic implementations like this on the server side, business logic is now moved into the client and becomes a client concern.
- If your API needs to do complex business logic over the CRUD functionality, please consider implementing custom endpoints instead of using generic endpoints such as this.
- There is currently no implementation for validation and DTO mapping, this can be added later as the project updates.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- Microsoft.AspNetCore.OpenApi (>= 8.0.10)
- Microsoft.EntityFrameworkCore (>= 8.0.10)
- Microsoft.EntityFrameworkCore.InMemory (>= 8.0.10)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.10)
- Russkyc.MinimalApi.Framework.Core (>= 0.8.0)
- System.Linq.Dynamic.Core (>= 1.4.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
- Refactor DbContext usage (migrate from per-entity context)
- Add migrations support (using a custom BaseDbContext implementation)